Поделиться через


Моменты, которые следует учитывать при отмене IRP

В этом разделе рассматриваются рекомендации по реализации процедуры отмены и обработке отменяемых IRP. Дополнительные сведения об обработке отменяемых irp см. в разделе Поток управления для очереди Cancel-Safe IRP.

Общие рекомендации по всем подпрограммам отмены

Диспетчер ввода-вывода удерживает блокировку отмены при вызове процедуры отмены отмены . Следовательно, каждая подпрограмма отмены должна:

  • Вызовите IoReleaseCancelSpinLock перед возвратом элемента управления.

  • Не вызывайте IoAcquireCancelSpinLock, если он не вызывает IoReleaseCancelSpinLock первым.

  • Сделайте обратный вызов IoReleaseCancelSpinLock для каждого вызова IoAcquireCancelSpinLock.

Каждый раз, когда подпрограмма Отмена вызывает IoReleaseCancelSpinLock, она должна передавать IRQL, возвращенный последним вызовом IoAcquireCancelSpinLock. При освобождении блокировки спина, полученной диспетчером ввода-вывода (и удерживаемой при вызове процедуры Отмена), подпрограмма Отмена должна передавать Irp-CancelIrql>.

Драйвер не должен вызывать внешние подпрограммы (например , IoCompleteRequest) при удержании блокировки спина, так как это может привести к взаимоблокировке.

Использование очереди, определенной диспетчером ввода-вывода

Если драйвер не управляет собственными внутренними очередями IRP, его подпрограмма Отмена вызывается с входящим IRP, который может иметь одно из следующих значений:

  • CurrentIrp во входном объекте целевого устройства

  • Запись в очереди устройств, связанная с целевым объектом устройства

Если драйвер не управляет собственными внутренними очередями IRP, его подпрограмма Отмена должна вызывать KeRemoveEntryDeviceQueue с входным IRP, чтобы проверить, является ли она записью в очереди устройства, связанной с целевым объектом устройства. Подпрограмма отмены драйвера не может вызывать KeRemoveDeviceQueue или KeRemoveByKeyDeviceQueue , так как она не может предположить, что указанная IRP находится в какой-либо определенной позиции в очереди устройств.

Текущее состояние входного IRP

Если подпрограмма отмены вызывается с IRP, для которой драйвер уже начал обработку ввода-вывода и запрос будет выполнен в ближайшее время, подпрограмма Отмена должна освободить системную отмену блокировки спина и управления возвратом.

Если текущее состояние входного IRP — Pending, подпрограмма Отмена должна выполнять следующие действия.

  1. Задайте блок состояния ввода-вывода IRP ввода-вывода, указав STATUS_CANCELLED для параметра Состояние и ноль для параметра Сведения.

  2. Отпустите все блокировки спина, которые он удерживает, включая системную блокировку спина отмены.

  3. Вызовите IoCompleteRequest с заданным IRP.

Удержание IRP в состоянии отменяемого выполнения

Любая подпрограмма драйвера, которая содержит IRP в отменяемом состоянии, должна вызывать IoMarkIrpPending и должна вызывать IoSetCancelRoutine , чтобы задать точку входа для подпрограммы Cancel в IRP. Только в этом случае эта подпрограмма драйвера может вызывать дополнительные подпрограммы поддержки, такие как IoStartPacket, IoAllocateController или ExInterlockedInsert.. Перечисление подпрограммы.

Любая подпрограмма драйвера, которая впоследствии обрабатывает отменяемые IRP, должна проверка, была ли уже отменена IRP до начала операций для удовлетворения запроса. Подпрограмма должна вызвать IoSetCancelRoutine , чтобы сбросить точку входа для подпрограммы Отмена в значение NULL в IRP. Только после этого эта подпрограмма может начать обработку ввода-вывода для входного IRP.

Подпрограмме может потребоваться сбросить точку входа для подпрограммы Отмена в IRP, если она также передает IRP для дальнейшей обработки другими подпрограммами драйвера, и эти IRP могут быть удержаны в состоянии отмены.

Любой драйвер более высокого уровня, который содержит IRP в отменяемом состоянии, должен сбросить свою точку входа Cancel в значение NULL , прежде чем он передает IRP в следующий более низкий драйвер с IoCallDriver.

Отмена IRP

Любой драйвер более высокого уровня может вызывать IoCancelIrp с IRP, который он выделил и передал для дальнейшей обработки драйверами более низкого уровня. Однако такой драйвер не может предполагать, что данный IRP будет заполнен с STATUS_CANCELLED более низкими драйверами.

Синхронизация

Драйвер может (или должен, в зависимости от его конструкции) хранить дополнительные сведения о состоянии в расширении устройства для отслеживания состояния irPs, допускающего отмену. Если это состояние совместно используется подпрограммами драйвера, работающими в IRQL <= DISPATCH_LEVEL, общие данные должны быть защищены с помощью выделенной драйвера и инициализированной спиновой блокировки.

Драйвер должен тщательно управлять своими приобретениями и выпусками системы отмены спин-блокировки и собственными спин-блокировками. Он должен удерживать блокировку спина отмены системы в течение кратчайшего интервала времени. Перед доступом к отменяемой IRP такой драйвер всегда должен проверка возвращаемое значение IoSetCancelRoutine, чтобы определить, запущена ли подпрограмма Отмена (или она будет запущена). Если это так, она должна позволить подпрограмме Отмена завершить IRP.

Если драйвер устройства хранит сведения о состоянии отменяемых IRP, которые различные подпрограммы драйвера совместно используют с его ISR, эти другие подпрограммы должны синхронизировать доступ к общему состоянию с ISR. Только предоставленная драйвером подпрограмма SynchCritSection может получить доступ к сведениям о состоянии, которые совместно используются с ISR в многопроцессорном режиме.

Дополнительные сведения см. в разделе Методы синхронизации.