IoCompletion 루틴 구현
항목에서 IoCompletion 루틴은 컨텍스트 포인터를 받습니다. 디스패치 루틴이 IoSetCompletionRoutine을 호출하면 컨텍스트 포인터를 제공할 수 있습니다. 이 포인터는 IoCompletion 루틴이 IRP를 처리하는 데 필요한 드라이버 결정 컨텍스트 정보를 참조할 수 있습니다. IoCompletion 루틴은 IRQL = DISPATCH_LEVEL 호출할 수 있으므로 컨텍스트 영역을 페이지할 수 없습니다.
IoCompletion 루틴에 대한 다음 구현 지침을 고려합니다.
IoCompletion 루틴은 IRP의 I/O 상태 블록을 검사 I/O 작업의 결과를 확인할 수 있습니다.
입력 IRP가 IoAllocateIrp 또는 IoBuildAsynchronousFsdRequest를 사용하여 디스패치 루틴에 의해 할당된 경우 IoCompletion 루틴은 원래 IRP를 완료하기 전에 해당 IRP를 해제하기 위해 IoFreeIrp 을 호출해야 합니다.
IoCompletion 루틴은 드라이버 할당 IRP에 할당된 디스패치 루틴을 IRP당 모든 리소스를 해제해야 하며, 가급적 해당 IRP를 해제하기 전에 해제해야 합니다.
예를 들어 디스패치 루틴이 IoAllocateMdl 을 사용하여 MDL을 할당하고 할당하는 부분 전송 IRP에 대해 IoBuildPartialMdl 을 호출하는 경우 IoCompletion 루틴은 IoFreeMdl을 사용하여 MDL을 해제해야 합니다. 원래 IRP에 대한 상태를 유지하기 위해 리소스를 할당하는 경우 원래 IRP를 사용하여 IoCompleteRequest 를 호출하기 전에 컨트롤을 반환하기 전에 해당 리소스를 해제해야 합니다.
일반적으로 IRP를 해제하거나 완료하기 전에 IoCompletion 루틴은 Dispatch 루틴에 의해 할당된 IRP당 리소스를 모두 해제해야 합니다. 그렇지 않으면 드라이버는 IoCompletion 루틴이 원래 요청을 완료하지 못하도록 컨트롤을 반환하기 전에 해제할 리소스에 대한 상태를 유지해야 합니다.
IoCompletion 루틴이 STATUS_SUCCESS 사용하여 원래 IRP를 완료할 수 없는 경우 원래 IRP의 I/O 상태 블록을 IoCompletion 루틴이 원래 요청에 실패하게 한 드라이버 할당 IRP에서 반환된 값으로 설정해야 합니다.
IoCompletion 루틴이 STATUS_PENDING 사용하여 원래 요청을 완료하는 경우 IoCompleteRequest를 호출하기 전에 원래 IRP를 사용하여 IoMarkIrpPending을 호출해야 합니다.
IoCompletion 루틴이 STATUS_XXX 오류와 함께 원래 IRP에 실패해야 하는 경우 오류를 기록할 수 있습니다. 그러나 발생하는 모든 디바이스 I/O 오류를 기록하는 것은 기본 디바이스 드라이버의 책임이므로 IoCompletion 루틴은 일반적으로 오류를 기록하지 않습니다.
IoCompletion 루틴이 드라이버 할당 IRP를 처리하고 해제한 경우 루틴은 STATUS_MORE_PROCESSING_REQUIRED 컨트롤을 반환해야 합니다.
IoCompletion 루틴에서 STATUS_MORE_PROCESSING_REQUIRED 반환하면 드라이버 할당 및 해제된 IRP에 대한 I/O 관리자의 완료 처리가 포리스트됩니다. IoCompleteRequest에 대한 두 번째 호출은 I/O 관리자가 IRP의 완료 루틴 호출을 다시 시작하도록 하며, 이는 STATUS_MORE_PROCESSING_REQUIRED 반환된 루틴 바로 위에 완료 루틴부터 시작합니다.
IoCompletion 루틴이 들어오는 IRP를 다시 사용하여 드라이버를 낮추기 위해 하나 이상의 요청을 보내거나 루틴이 실패한 작업을 다시 시도하는 경우 IoCompletion 루틴이 IRP의 각 재사용 또는 재시도에 대해 유지 관리하는 컨텍스트를 업데이트해야 합니다. 그런 다음, 다음으로 낮은 드라이버의 I/O 스택 위치를 다시 설정하고, 자체 진입점으로 IoSetCompletionRoutine 을 호출하고, IRP에 대해 IoCallDriver 를 호출할 수 있습니다.
IoCompletion 루틴은 IRP를 다시 사용하거나 다시 시도할 때마다 IoMarkIrpPending을 호출해서는 안 됩니다.
디스패치 루틴은 이미 원래 IRP를 보류 중으로 표시했습니다. 체인의 모든 드라이버가 IoCompleteRequest를 사용하여 원래 IRP를 완료할 때까지 보류 중인 상태로 유지됩니다.
요청을 다시 시도하기 전에 IoCompletion 루틴은 반환된 오류 정보를 저장한 후 상태 및 정보에 대한 STATUS_SUCCESS 사용하여 I/O 상태 블록을 다시 설정해야 합니다.
재시도할 때마다 IoCompletion 루틴은 일반적으로 디스패치 루틴에 의해 설정된 재시도 횟수를 감소합니다. 일반적으로 IoCompletion 루틴은 제한된 수의 재시도에 실패한 경우 IRP에 실패하기 위해 IoCompleteRequest 를 호출해야 합니다.
IoCompletion 루틴은 다시 사용하거나 다시 시도 중인 IRP를 사용하여 IoSetCompletionRoutine 및 IoCallDriver를 호출한 후 STATUS_MORE_PROCESSING_REQUIRED 반환해야 합니다.
IoCompletion 루틴에서 STATUS_MORE_PROCESSING_REQUIRED 반환하면 다시 사용되거나 다시 시도된 IRP에 대한 I/O 관리자의 완료 처리가 포리스트됩니다.
IoCompletion 루틴이 STATUS_SUCCESS 사용하여 원래 IRP를 완료할 수 없는 경우 IoCompletion 루틴이 IRP에 실패하도록 하는 다시 사용 또는 재시도 작업을 위해 낮은 드라이버에서 반환한 대로 I/O 상태 블록을 유지해야 합니다.
IoCompletion 루틴이 STATUS_PENDING 사용하여 원래 요청을 완료하는 경우 IoCompleteRequest를 호출하기 전에 원래 IRP를 사용하여 IoMarkIrpPending을 호출해야 합니다.
IoCompletion 루틴이 STATUS_XXX 오류와 함께 원래 IRP에 실패해야 하는 경우 오류를 기록할 수 있습니다. 그러나 발생하는 모든 디바이스 I/O 오류를 기록하는 것은 기본 디바이스 드라이버의 책임이므로 IoCompletion 루틴은 일반적으로 오류를 기록하지 않습니다.
IRP에서 IoCompletion 루틴을 설정한 다음 IRP를 하위 드라이버로 전달하는 모든 드라이버는 IoCompletion 루틴에서 IRP-PendingReturned> 플래그를 검사 합니다. 플래그가 설정된 경우 IoCompletion 루틴은 IRP를 사용하여 IoMarkIrpPending을 호출해야 합니다. 그러나 IRP를 전달한 다음 이벤트를 기다리는 드라이버는 IRP 보류 중으로 표시해서는 안 됩니다. 대신 IoCompletion 루틴은 이벤트를 신호로 표시하고 STATUS_MORE_PROCESSING_REQUIRED 반환해야 합니다.
IoCompletion 루틴은 원래 IRP를 처리하기 위해 할당된 디스패치 루틴을 해제해야 합니다. 가급적 IoCompletion 루틴이 원래 IRP를 사용하여 IoCompleteRequest를 호출하기 전과 IoCompletion 루틴이 원래 IRP를 완료하지 못하도록 제어를 반환하기 전에 해제해야 합니다.
상위 수준 드라이버가 원래 IRP에서 IoCompletion 루틴을 설정한 경우 모든 하위 수준 드라이버의 IoCompletion 루틴이 호출될 때까지 해당 드라이버의 IoCompletion 루틴이 호출되지 않습니다.
IoCompleteRequest 호출에서 우선 순위 향상 제공
최하위 수준 디바이스 드라이버가 디스패치 루틴에서 IRP를 완료할 수 있는 경우 priorityBoost가 IO_NO_INCREMENT IoCompleteRequest를 호출합니다. 드라이버는 원래 요청자가 I/O 작업이 완료될 때까지 기다리지 않았다고 가정할 수 있으므로 런타임 우선 순위 증가가 필요하지 않습니다.
그렇지 않으면 최저 수준 드라이버는 요청자가 디바이스 I/O 요청에서 대기한 시간을 보상하기 위해 요청자의 런타임 우선 순위를 높이는 시스템 정의 및 디바이스 유형별 값을 제공합니다. 부스트 값은 Wdm.h 또는 Ntddk.h를 참조하세요.
상위 수준 드라이버는 IoCompleteRequest를 호출할 때 해당 기본 디바이스 드라이버와 동일한 PriorityBoost를 적용합니다.
IoCompleteRequest 호출의 효과
드라이버가 IoCompleteRequest를 호출하면 I/O 관리자는 IRP에 대해 호출할 IoCompletion 루틴을 설정한 다음 상위 수준 드라이버를 호출하기 전에 해당 드라이버의 I/O 스택 위치를 0으로 채웁니다.
상위 수준 드라이버의 IoCompletion 루틴은 IRP의 I/O 상태 블록만 검사 모든 하위 드라이버가 요청을 처리하는 방법을 결정할 수 있습니다.
IoCompleteRequest의 호출자는 방금 완료된 IRP에 액세스하려고 시도해서는 안됩니다. 이러한 시도는 시스템 충돌을 일으키는 프로그래밍 오류입니다.