다음을 통해 공유


IoCompletion 루틴 등록

IoCompletion 루틴을 등록하기 위해 디스패치 루틴은 IoSetCompletionRoutine을 호출하여 IoCompletion 루틴의 주소와 이후에 IoCallDriver를 사용하여 낮은 드라이버에 전달할 IRP를 제공합니다.

IoSetCompletionRoutine을 호출할 때 디스패치 루틴은 I/O 관리자가 지정된 IoCompletion 루틴을 호출해야 하는 상황을 지정합니다. 하위 수준 드라이버가 IRP를 성공적으로 완료하거나(InvokeOnSuccess) 오류 상태 값으로 IRP를 완료하거나(InvokeOnError) 어떤 조합으로든 IRP(InvokeOnCancel)를 취소하는 경우 IoCompletion 루틴을 호출하도록 선택할 수 있습니다.

IoCompletion 루틴의 목적은 IRP에서 하위 수준 드라이버가 수행한 작업을 모니터링하고 필요한 경우 추가 완료 처리를 수행하는 것입니다. 특히 드라이버의 IoCompletion 루틴에 가장 일반적인 용도는 다음과 같습니다.

  • 드라이버가 IoAllocateIrp 또는 IoBuildAsynchronousFsdRequest로 할당한 IRP를 삭제하려면

    이러한 지원 루틴 중 하나를 사용하여 IRP를 할당하는 상위 수준 드라이버는 해당 IRP에 대한 IoCompletion 루틴을 제공해야 합니다. IoCompletion 루틴은 드라이버 할당 IRP를 삭제하려면 IoFreeIrp을 호출해야 합니다.

  • 들어오는 IRP를 다시 사용하여 IoCompletion 루틴에서 원래 요청을 충족하고 완료할 수 있을 때까지 하위 드라이버가 부분 전송과 같은 일부 작업을 완료하도록 요청합니다.

  • 낮은 드라이버가 오류와 함께 완료된 요청을 다시 시도하려면

    파일 시스템과 같은 최고 수준의 드라이버는 밀접하게 결합된 포트 드라이버 위에 계층화된 클래스 드라이버를 제외하고 중간 드라이버보다 요청을 다시 시도하려는 IoCompletion 루틴이 있을 가능성이 더 높습니다. 그러나 모든 중간 드라이버는 IoCompletion 루틴을 사용하여 요청을 다시 시도합니다.

최고 수준 또는 중간 드라이버의 DispatchReadWrite 루틴은 IoCompletion 루틴이 필요한 IRP를 처리할 가능성이 가장 높지만, IRP를 하위 드라이버로 전달하는 모든 드라이버의 디스패치 루틴은 IoCompletion 루틴을 등록할 수 있습니다.

드라이버 할당 IRP 및 재사용된 IRP의 경우 디스패치 루틴은 다음 부울 매개 변수를 사용하여 IoSetCompletionRoutine 을 호출해야 합니다.

  • InvokeOnSuccess가TRUE로 설정

  • InvokeOnError가TRUE로 설정

  • 체인의 하위 드라이버가 취소 가능한 IRP를 처리할 수 있는 경우 InvokeOnCancelTRUE로 설정됩니다.

    일반적으로 InvokeOnCancel은 IRP가 STATUS_CANCELLED 함께 반환될 수 있는지 여부에 관계없이 TRUE로 설정되므로 IoCompletion 루틴이 드라이버가 할당한 각 IRP를 해제하거나 IRP의 각 재사용에 대한 완료 상태 확인합니다.

IoAllocateIrp 또는 IoBuildAsynchronousFsdRequest를 사용하여 하위 드라이버에 대해 IRP를 할당하는 디스패치 루틴은 드라이버가 할당한 각 IRP에 대해 IoCompletion 루틴을 설정해야 합니다.

  • 디스패치 루틴은 사용할 IoCompletion 루틴에 대해 원래 IRP 및 할당된 IRP에 대한 상태를 설정해야 합니다. 최소한 IoCompletion 루틴은 원래 IRP에 대한 액세스 권한과 할당된 추가 IR 수의 수를 필요로 합니다.

  • 디스패치 루틴은 할당하는 IRP에 대해 모든 InvokeOnXxx 매개 변수가 TRUE로 설정된 IoSetCompletionRoutine을 호출해야 합니다.

일련의 작업에 IRP를 다시 사용하거나 I/O 작업을 다시 시도하는 디스패치 루틴은 다시 사용하거나 다시 시도될 각 IRP에 대해 IoSetCompletionRoutine 을 호출해야 합니다.

  • 디스패치 루틴은 IoCompletion 루틴에서 나중에 사용하기 위해 원래 IRP의 상태 정보를 저장해야 합니다.

    예를 들어 DispatchReadWrite 루틴은 해당 IRP의 다음 하위 드라이버에 대한 부분 전송을 설정하기 전에 IoCompletion 루틴에 대한 입력 IRP의 관련 전송 매개 변수를 저장해야 합니다. DispatchReadWrite 루틴이 IoCompletion 루틴에서 원래 요청이 충족된 시기를 결정하는 데 필요한 매개 변수를 수정하는 경우 매개 변수를 저장하는 것이 특히 중요합니다.

  • IoCompletion 루틴이 요청을 다시 시도할 수 있는 경우 디스패치 루틴은 오류와 함께 원래 IRP를 완료하기 전에 IoCompletion 루틴이 시도해야 하는 재시도 횟수에 대해 드라이버 결정 상한을 설정해야 합니다.

  • IRP를 다시 사용할 경우 디스패치 루틴은 모든 InvokeOnXxx 매개 변수가 TRUE로 설정된 IoSetCompletionRoutine을 호출해야 합니다.

  • 비동기 요청의 경우 중간 드라이버의 디스패치 루틴은 원래 IRP 에 대해 IoMarkIrpPending을 호출해야 합니다. 그런 다음 IRP를 낮은 드라이버로 보낸 후 STATUS_PENDING 반환해야 합니다.