IRP look-aside list) хранит IRP с одним блоком стека (об этих блоках — чуть позже), а ассоциативный список больших IRP (large-IRP look-aside list) — IRP с несколькими блоками стека. По умолчанию в IRP второго списка содержится 8 блоков стека, но раз в минуту система варьирует это число на основании того, сколько блоков было запрошено. Если для IRP требуется больше блоков стека, чем имеется в ассоциативном списке больших IRP, диспетчер ввода-вывода выделяет память под IRP из пула неподкачиваемой памяти. После создания и инициализации IRP диспетчер ввода-вывода сохраняет в IRP указатель на объект «файл» вызывающего потока.

ПРИМЕЧАНИЕ DWORD-параметр реестра HKLM\System\CurrentControlSet\Session Manager\I/O System\LargIrpStackLocations (если он определен) указывает, сколько блоков стека содержится в IRP, которые хранятся в ассоциативном списке больших IRP

Ha рис. 9–9 показан пример запроса ввода-вывода, демонстрирующий взаимосвязи между IRP и объектами «файл», «устройство» и «драйвер». Данный пример относится к запросу ввода-вывода, который адресован одноуровневому драйверу, но большинство операций ввода-вывода гораздо сложнее, так как в их выполнении участвует не один, а несколько многоуровневых драйверов. (Этот случай мы рассмотрим позже.)

3.Внутреннее устройство Windows (гл. 8-11) pic_65.png
Блок стека IRP

IRP состоит из двух частей: фиксированного заголовка (часто называемого телом IRP) и одного или нескольких блоков стека. Фиксированная часть содержит такую информацию, как тип и размер запроса, указатель на буфер в случае буферизованного ввода-вывода, данные о состоянии, изменяющиеся по мере обработки запроса, а также сведения о том, является запрос синхронным или асинхронным. Блок стека IRP (IRP stack location) содержит номер функции (состоящий из основного и дополнительного номеров), параметры, специфичные для функции, и указатель на объект «файл» вызывающего потока. Основной номер функции (major function code) идентифицирует принадлежащую драйверу процедуру диспетчеризации, которую диспетчер ввода-вывода вызывает при передаче IRP драйверу. Необязательный дополнительный номер функции (minor function code) иногда используется как модификатор основного номера. B командах управления электропитанием и Plug and Play всегда указывается дополнительный номер функции.

B большинстве драйверов процедуры диспетчеризации определены только для подмножества основных функций, т. е. функций, предназначенных для создания/открытия, записи, чтения, управления вводом-выводом на устройстве, управления электропитанием, операций Plug and Play, System (для WMI-команд) и закрытия. Драйверы файловой системы определяют функции для всех (или почти всех) точек входа. Диспетчер ввода-вывода записывает в точки входа, не заполненные драйверами, указатели на свою функцию IopInvalidDeviceRequest. Эта функция возвращает вызывающему потоку код ошибки, который уведомляет о попытке обращения к функции, не поддерживаемой данным устройством.

ЭКСПЕРИМЕНТ: исследуем процедуры диспетчеризации, принадлежащие драйверу

Вы можете получить список всех функций, определенных драйвером для своих процедур диспетчеризации. Для этого введите команду !drvobj отладчика ядра и после имени (или адреса) объекта «драйвер» укажите значение 7. Следующий вывод показывает, что драйверы поддерживают 28 типов IRR

3.Внутреннее устройство Windows (гл. 8-11) pic_66.png
3.Внутреннее устройство Windows (гл. 8-11) pic_67.png
3.Внутреннее устройство Windows (гл. 8-11) pic_68.png

Каждый IRP, пока он активен, хранится в списке IRP, сопоставленном с потоком, который выдал запрос на ввод-вывод. Это позволяет подсистеме ввода-вывода найти и отменить любые незавершенные IRP, если выдавший их поток завершается.

ЭКСПЕРИМЕНТ: просмотр незавершенных IRP потока

Команда !thread выводит любые IRP, сопоставленные с потоком. Запустите отладчик ядра в работающей системе и найдите процесс диспетчера управления сервисами (Services.exe) в выводе, сгенерированном командой !process\

3.Внутреннее устройство Windows (гл. 8-11) pic_69.png

Теперь создайте дамп потоков для процесса, выполнив команду !process применительно к объекту «процесс». Вы должны увидеть множество потоков, у большинства из которых есть IRP; эти IRP отображаются в блоке IRP List информации о потоке (заметьте, что отладчик выводит лишь первые 17 IRP для потока, у которого имеется более 17 незавершенных запросов ввода-вывода):

3.Внутреннее устройство Windows (гл. 8-11) pic_70.png
3.Внутреннее устройство Windows (гл. 8-11) pic_71.png

У этого IRP основной номер функции — 3, что соответствует IRP_ MJ_READ. Он содержит один блок стека и адресован устройству, принадлежащему драйверу Npfs (Named Pipe File System). (Информацию о Npfs см. в главе 13.)

Управление буфером IRP

Когда приложение или драйвер устройства неявно создает IRP с помощью системного сервиса NtReadFile, NtWriteFile или NtDeviceIoControlFile (этим сервисам соответствуют Windows-функции ReadFile, WriteFile и DeviceIoControt), диспетчер ввода-вывода определяет, должен ли он участвовать в управлении буферами ввода и вывода вызывающего потока. Диспетчер ввода-вывода поддерживает три вида управления буферами.

• Буферизованный ввод-вывод (buffered I/O) Диспетчер ввода-вывода выделяет в пуле неподкачиваемой памяти буфер, равный по размеру буферу вызывающего потока. Создавая IRP при операциях записи, диспетчер ввода-вывода копирует данные из буфера вызывающего потока в выделенный буфер. Завершая обработку IRP при операциях чтения, диспетчер ввода-вывода копирует данные из выделенного буфера в пользовательский буфер и освобождает выделенный буфер.

• Прямой ввод-вывод (direct I/O) Создавая IRP, диспетчер ввода-вывода блокирует пользовательский буфер в памяти (делает его неподкачиваемым). Закончив работу с IRP, диспетчер ввода-вывода разблокирует буфер. Диспетчер хранит описание этой памяти в форме MDL (memory descriptor list). MDL указывает объем физической памяти, занятой буфером (подробнее о MDL см. Windows DDK). Устройствам, использующим DMA (прямой доступ к памяти), требуется лишь физическое описание буфера, поэтому таким устройствам достаточно MDL. (Устройства, поддерживающие DMA, передают данные в память компьютера напрямую, не используя процессор.) Ho, если драйверу нужен доступ к содержимому буфера, он может спроецировать его на системное адресное пространство.

• Ввод-вывод без управления (neither I/O) Диспетчер ввода-вывода не участвует в управлении буферами. Ответственность за управление ими возлагается на драйвер устройства.

При любом типе управления буферами диспетчер ввода-вывода помещает в IRP ссылки на буферы ввода и вывода. Тип управления буферами, реализуемого диспетчером ввода-вывода, зависит от типа управления, запрошенного драйвером для операций конкретного типа. Драйвер регистрирует нужный ему тип управления буферами для операций чтения и записи в объекте «устройство», который представляет устройство. Операции управления вводом-выводом на устройстве (выполняемые NtDeviceIoControlFile) задаются определенными в драйвере управляющими кодами ввода-вывода. Управляющий код включает тип управления буферами со стороны диспетчера ввода-вывода при обработке IRP с данным кодом.

Когда вызывающие потоки передают запросы размером менее одной страницы (4 Кб на х86-процессорах), драйверы, как правило, используют буферизованный ввод-вывод, а для запросов большего размера — прямой. Буфер примерно равен размеру страницы, и операция копирования с применением буферизованного ввода-вывода приводит практически к тем же издержкам, что и прямой ввод-вывод, требующий блокирования памяти. Драйверы файловой системы обычно используют третий тип управления, так как при копировании данных из кэша файловой системы в буфер вызывающего потока это позволяет избавиться от издержек, связанных с управлением буферами. Ho большинство драйверов не использует этот вид управления из-за того, что указатель на буфер вызывающего потока действителен лишь на то время, пока выполняется этот поток. Если драйверу нужно передать данные с устройства (или на устройство) при выполнении DPC-процедуры или ISR, он должен позаботиться о доступности данных вызывающего потока из контекста любого процесса, а значит, у буфера должен быть системный виртуальный адрес.


Перейти на страницу:
Изменить размер шрифта: