Самоучитель по программированию систем защиты

       

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



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

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

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

PDRIVER_CANCEL loSetCancelRoutine(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 не может быть отменен или не принадлежит драйверу, то надо освободить системную спин-блокировку и завершить работу функции.
  • В противном случае:
  • 1. удалить пакет IRP из любых очередей, в которых он присутствует;
  • 2. установить функцию отмены IRP в NULL с помощью IoSetCancelRoutine();
  • 3. освободить системную спин-блокировку;
  • 4. установить в IRP поле loStatus.Information равном 0, а поле loStatus.Status равном STATUS_CANCELLED;
  • 5. завершить IRP с помощью loCompleteRequest().
  • Системная спин-блокировка отмены IRP освобождается с помощью loRelease CancelSpinLock():

    VOID IoReleaseCancelSpinLock(IN KIRQL Irgl);

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



    Содержание раздела