Share via


IRP를 취소할 때 고려해야 할 사항

이 섹션에서는 취소 루틴을 구현하고 취소 가능한 IRP를 처리하기 위한 지침을 설명합니다. 취소 가능한 IRP 처리에 대한 자세한 내용은 Cancel-Safe IRP 큐에 대한 제어 흐름을 참조하세요.

모든 취소 루틴에 대한 일반 지침

I/O 관리자는 드라이버의 취소 루틴을 호출할 때마다 취소 스핀 잠금을 유지합니다. 따라서 모든 취소 루틴은 다음을 수행해야 합니다.

  • 컨트롤을 반환하기 전에 IoReleaseCancelSpinLock 을 호출합니다.

  • IoReleaseCancelSpinLock을 먼저 호출하지 않는 한 IoAcquireCancelSpinLock을 호출하지 않습니다.

  • IoAcquireCancelSpinLock에 대해 호출할 때마다 IoReleaseCancelSpinLock을 상호 호출합니다.

Cancel 루틴이 IoReleaseCancelSpinLock을 호출할 때마다 IoAcquireCancelSpinLock에 대한 최신 호출에서 반환된 IRQL을 전달해야 합니다. I/O 관리자가 획득한 스핀 잠금을 해제하고 취소 루틴이 호출될 때 유지되는 경우 취소 루틴은 Irp-CancelIrql>을 통과해야 합니다.

교착 상태가 발생할 수 있으므로 드라이버가 스핀 잠금을 보유하는 동안 외부 루틴(예: IoCompleteRequest)을 호출해서는 안 됩니다.

I/O 관리자가 정의한 큐 사용

드라이버가 자체 내부 IRP 큐를 관리하지 않는 한 다음 중 하나일 수 있는 들어오는 IRP를 사용하여 Cancel 루틴이 호출됩니다.

  • 입력 대상 디바이스 개체의 CurrentIrp

  • 대상 디바이스 개체와 연결된 디바이스 큐의 항목

드라이버가 자체 IRP의 내부 큐를 관리하지 않는 한 Cancel 루틴은 입력 IRP를 사용하여 KeRemoveEntryDeviceQueue 를 호출하여 대상 디바이스 개체와 연결된 디바이스 큐의 항목인지 테스트해야 합니다. 드라이버의 Cancel 루틴은 지정된 IRP가 디바이스 큐의 특정 위치에 있다고 가정할 수 없 으므로 KeRemoveDeviceQueue 또는 KeRemoveByKeyDeviceQueue 를 호출할 수 없습니다.

입력 IRP의 현재 상태

드라이버가 이미 I/O 처리를 시작한 IRP를 사용하여 취소 루틴이 호출되고 요청이 곧 완료될 경우 취소 루틴은 시스템 취소 스핀 잠금 및 반환 컨트롤을 해제해야 합니다.

입력 IRP의 현재 상태가 보류 중이면 Cancel 루틴에서 다음을 수행해야 합니다.

  1. 입력 IRP의 I/O 상태 블록을 상태의 STATUS_CANCELLED, 정보에 대해 0으로 설정합니다.

  2. 시스템 취소 스핀 잠금을 포함하여 보유하고 있는 모든 스핀 잠금을 해제합니다.

  3. 지정된 IRP를 사용하여 IoCompleteRequest 를 호출합니다.

취소 가능한 상태로 IRP 보유

취소 가능한 상태의 IRP를 보유하는 모든 드라이버 루틴은 IoMarkIrpPending을 호출해야 하며 IoSetCancelRoutine 을 호출하여 IRP의 Cancel 루틴에 대한 진입점을 설정해야 합니다. 그런 다음에만 해당 드라이버 루틴은 IoStartPacket, IoAllocateController 또는 ExInterlockedInsert와 같은 추가 지원 루틴을 호출할 수 있습니다 . 루틴을 나열 합니다.

이후에 취소 가능한 IRP를 처리하는 모든 드라이버 루틴은 요청을 충족하기 위해 작업을 시작하기 전에 IRP가 이미 취소되었는지 여부를 검사 합니다. 루틴은 IRP에서 Cancel 루틴의 진입점을 NULL로 다시 설정하려면 IoSetCancelRoutine을 호출해야 합니다. 그런 다음에만 해당 루틴이 입력 IRP에 대한 I/O 처리를 시작할 수 있습니다.

루틴은 IRP에서 취소 루틴의 진입점을 다시 설정해야 할 수 있습니다. 또한 다른 드라이버 루틴의 추가 처리를 위해 IRP를 전달하고 해당 IRP가 취소 가능한 상태로 유지될 수 있습니다.

취소 가능한 상태로 IRP를 보유하는 상위 수준 드라이버는 IRP를 IoCallDriver로 다음 하위 드라이버에 전달하기 전에 취소 진입점을 NULL로 다시 설정해야 합니다.

IRP 취소

모든 상위 수준 드라이버는 하위 수준 드라이버에서 추가 처리를 위해 할당하고 전달한 IRP를 사용하여 IoCancelIrp 을 호출할 수 있습니다. 그러나 이러한 드라이버는 지정된 IRP가 낮은 드라이버에 의해 STATUS_CANCELLED 완료될 것이라고 가정할 수 없습니다.

동기화

드라이버는 디자인에 따라 디바이스 확장에서 추가 상태 정보를 유지 관리하여 취소 가능한 IRP 상태 추적할 수 있습니다. IRQL <= DISPATCH_LEVEL 실행되는 드라이버 루틴에서 이 상태를 공유하는 경우 공유 데이터는 드라이버 할당 및 초기화된 스핀 잠금으로 보호되어야 합니다.

드라이버는 시스템 취소 스핀 잠금 및 자체 스핀 잠금의 인수 및 릴리스를 신중하게 관리해야 합니다. 가능한 가장 짧은 간격 동안 시스템 취소 스핀 잠금을 유지해야 합니다. 취소 가능한 IRP에 액세스하기 전에 이러한 드라이버는 항상 IoSetCancelRoutine의 반환 값을 검사 취소 루틴이 이미 실행 중인지 또는 실행 중인지 확인해야 합니다. 이 경우 취소 루틴이 IRP를 완료하도록 해야 합니다.

디바이스 드라이버가 다양한 드라이버 루틴이 ISR과 공유하는 취소 가능한 IRP에 대한 상태 정보를 유지 관리하는 경우 이러한 다른 루틴은 ISR과 공유 상태에 대한 액세스를 동기화해야 합니다. 드라이버에서 제공하는 SynchCritSection 루틴만 다중 프로세서로부터 안전한 방식으로 ISR과 공유되는 상태 정보에 액세스할 수 있습니다.

자세한 내용은 동기화 기술을 참조하세요.