Отмена IRP и Системная Очередь

Отмена запросов в/в

Всякий раз, когда запрос в/в удерживается драйвером в течение продолжительного отрезка времени, драйвер должен быть готов к отмене данного запроса. В случае закрытия потока диспетчер в/в пытается отменить все запросы в/в, отправленные этим потоком и еще не завершенные. Пока все такие запросы в/в не будут завершены устройством, ему не придет запрос IRP_MJ_CLOSE, и, следовательно, не освободится объект-файл, а впоследствии – и само устройство (драйвер никогда не получит запрос DriverUnload).

Для обеспечения отмены запроса в/в в пакете IRP, представляющем такой запрос, должен быть указан адрес диспетчерской точки входа драйвера, собственно отменяющей запрос. Для этого служит функция IoSetCancelRoutine().

PDRIVER_CANCEL IoSetCancelRoutine (IN PIRP Irp, PDRIVER_CANCEL CancelRoutine);

Функция CancelRoutine() имеет такой же прототип, как и все диспетчерские функции.

VOID CancelRoutine (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

Она вызывается на уровне IRQL DISPATCH_LEVEL в случайном контексте потока, однако перед ее вызовом происходит захват специальной системной спин-блокировки. До тех пор, пока системная спин-блокировка не будет освобождена, функция CancelRoutine() работает на уровне IRQL DISPATCH_LEVEL. Уровень IRQL, на который нужно перейти после освобождения блокировки указывается при вызове IoReleaseCancelSpinLock() (см. ниже). Принцип реализации функции следующий:

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

· В противном случае:

· удалить пакет IRP из любых очередей, в которых он присутствует

· установить функцию отмены IRP в NULL с помощью IoSetCancelRoutine()

· освободить системную спин-блокировку

· установить в IRP поле IoStatus.Information=0, IoStatus.Status=STATUS_CANCELLED

· завершить IRP с помощью IoCompleteRequest().

Системная спин-блокировка отмены IRP освобождается с помощью IoReleaseCancelSpinLock()

VOID IoReleaseCancelSpinLock(IN KIRQL Irql);

где Irql – уровень IRQL, на который система должна вернуться после освобождения спин-блокировки. Это значение хранится в IRP в поле CancelIrql.

Пример функции отмены IRP драйвера, использующего системную очередь, показан в следующем листинге. Необходимо отметить, что для удаления IRP из системной очереди используется функция KeRemoveEntryDeviceQueue() так, как это показано в листинге.

VOID Cancel(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

{

// Обрабатывается ли отменяемый запрос в данный момент?

if (Irp == DeviceOb]ect->CurrentIrp)

{

// Да. Освободить системную спин-блокировку и указать диспетчеру в/в

// начать обработку следующего пакета. Отмена IRP – в конце функции

IoReleaseCancelSpinLock(Irp->CancelIrql);

IoStartNextPacket(DeviceOb]ect, TRUE);

}

else

{

// Нет. Отменяемый IRP находится в очереди. Удалить его из очереди

KeRemoveEntryDeviceQueue(&DeviceOb]ect->DeviceQueue,

&Irp->Tail.Overlay.DeviceQueueEntry);

IoReleaseCancelSpinLock(Irp->CancelIrql);

}

// Отменить IRP

Irp->IoStatus.Status = STATUS_CANCELLED;

Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

return;

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: