Share via


Intermediate-Level 드라이버에서 IRP 처리

상위 수준 드라이버는 최저 수준 디바이스 드라이버와 다른 표준 루틴 집합을 가지며, 두 유형의 드라이버에 공통적인 표준 루틴의 하위 집합이 겹칩니다.

중간 및 최고 수준의 드라이버에 대한 루틴 집합도 다음 기준에 따라 달라집니다.

  • 기본 물리적 디바이스의 특성

  • 기본 디바이스 드라이버가 직접 또는 버퍼링된 I/O에 대한 디바이스 개체를 설정하는지 여부

  • 개별 상위 수준 드라이버의 디자인

다음 그림에서는 IRP가 이전 섹션에서 설명한 가장 낮은 수준의 디바이스 드라이버 위에 계층화된 중간 미러 드라이버의 표준 루틴을 통해 수행할 수 있는 경로를 보여 줍니다.

다음 그림에 표시된 드라이버의 특징은 다음과 같습니다.

  • 드라이버는 둘 이상의 물리적 디바이스와 둘 이상의 디바이스 드라이버를 통해 계층화됩니다.

  • 드라이버는 입력 IRP에서 요청된 작업에 따라 하위 수준 드라이버에 대해 추가 IRP를 할당하는 경우가 있습니다.

  • 드라이버에는 하나 이상의 파일 시스템 드라이버가 계층화되어 있으며 해당 파일 시스템 드라이버는 이 드라이버보다 높은 수준에서 다른 중간 드라이버보다 계층화될 수 있습니다.

중간 드라이버 루틴을 통한 irp 경로를 보여 주는 다이어그램

그림과 같이 I/O 관리자는 IRP를 만들고 지정된 주 함수 코드에 대한 드라이버의 디스패치 루틴으로 보냅니다. 함수 코드가 IRP_MJ_WRITE 경우 디스패치 루틴은 DDDispatchWrite입니다. 중간 드라이버의 I/O 스택 위치는 중간에 표시되며, 셰이딩된 것으로 표시된 상위 및 하위 수준 드라이버에 대한 I/O 스택 위치는 무기한으로 표시됩니다.

IRP 할당

미러 드라이버의 목적은 여러 물리적 디바이스에 쓰기 요청을 보내고 이러한 디바이스의 드라이버에 번갈아 읽기 요청을 보내는 것입니다. 쓰기 요청의 경우 드라이버는 입력 IRP의 매개 변수가 유효하다고 가정하여 데이터를 쓸 각 디바이스에 대해 중복 IRP를 만듭니다.

이전 그림에서는 IoAllocateIrp 에 대한 호출을 보여 주지만 상위 수준 드라이버는 다른 지원 루틴을 호출하여 하위 수준 드라이버에 대한 IRP를 할당할 수 있습니다. Lower-Level 드라이버에 대한 IRP 만들기를 참조하세요.

디스패치 루틴이 IoAllocateIrp을 호출할 때 IRP에 필요한 I/O 스택 위치 수를 지정합니다. 드라이버는 체인의 각 하위 드라이버에 대한 스택 위치를 지정하여 미러 드라이버 바로 아래에 있는 각 드라이버의 디바이스 개체에서 적절한 값을 얻어야 합니다. 필요에 따라 드라이버는 IoAllocateIrp 을 호출하여 이전 그림의 드라이버처럼 할당하는 각 IRP에 대한 자체 스택 위치를 가져올 때 이 값에 하나를 추가할 수 있습니다.

이 중간 드라이버의 디스패치 루틴은 원래 IRP를 사용하여 IoGetCurrentIrpStackLocation(표시되지 않음)을 호출하여 매개 변수를 검사.

새로 만든 각 IRP 및 IoGetCurrentIrpStackLocation에 자체 스택 위치를 할당하여 나중에 IoCompletion 루틴에서 사용하는 컨텍스트를 만들기 때문에 IoSetNextIrpStackLocation을 호출합니다.

다음으로, 새로 만든 각 IRP를 사용하여 IoGetNextIrpStackLocation 을 호출하므로 할당된 IRP에서 다음 하위 수준 드라이버의 I/O 스택 위치를 설정할 수 있습니다. 미러 드라이버의 디스패치 루틴은 IRP 함수 코드 및 매개 변수(전송 버퍼에 대한 포인터, IRP_MJ_WRITE 전송할 길이(바이트))를 다음 하위 드라이버의 I/O 스택 위치에 복사합니다. 이러한 드라이버는 드라이버 바로 아래에 있는 드라이버에 대한 I/O 스택 위치(있는 경우)를 설정합니다.

IoSetCompletionRoutine 및 IoCallDriver 호출

이전 그림의 디스패치 루틴은 할당된 각 IRP에 대해 IoSetCompletionRoutine 을 호출합니다. 이전 그림의 드라이버는 할당된 IRP를 삭제해야 하므로 이 드라이버는 I/O 작업이 성공적으로 완료되었는지, 실패했는지 또는 취소되었는지 여부에 관계없이 낮은 드라이버가 IRP를 완료할 때 IoCompletion 루틴을 호출하도록 설정합니다.

이전 그림의 드라이버는 병렬로 미러링되므로 미러된 파티션을 나타내는 각 대상 디바이스 개체에 대해 한 번씩 IoCallDriver 를 두 번 호출하여 할당된 두 IRP를 다음 하위 수준 드라이버에 전달합니다.

드라이버의 IoCompletion 루틴에서 IRP 처리

하위 수준 드라이버 집합 중 하나가 요청된 작업을 완료하면 I/O 관리자는 중간 미러 드라이버의 IoCompletion 루틴을 호출합니다. 미러 드라이버는 하위 드라이버가 모든 중복 IRP를 완료한 시점을 추적하기 위해 원래 IRP에 대한 자체 I/O 스택 위치에 카운트를 유지합니다.

I/O 상태 블록이 이전 그림에 표시된 중복 IRP를 완료했다고 가정하면 미러 드라이버의 IoCompletion 루틴은 개수를 감소하지만 개수를 0으로 줄일 때까지 원래 IRP를 완료할 수 없습니다. 감소된 수가 아직 0이 아니면 IoCompletion 루틴은 드라이버가 할당하고 STATUS_MORE_PROCESSING_REQUIRED 반환하는 첫 번째 반환 IRP(이전 그림의 DupIRP1)를 사용하여 IoFreeIrp 을 호출합니다.

이전 그림에 표시된 DupIRP2를 사용하여 미러 드라이버의 IoCompletion 루틴이 다시 호출되면 IoCompletion 루틴은 원래 IRP의 수를 감소시키고 두 하위 수준 드라이버 집합이 모두 요청된 작업을 수행했는지 확인합니다.

DupIRP2의 I/O 상태 블록도 STATUS_SUCCESS 설정되어 있다고 가정하면 IoCompletion 루틴은 DupIRP2의 I/O 상태 블록을 원래 IRP로 복사하고 DupIRP2를 해제합니다. 원래 IRP를 사용하여 IoCompleteRequest 를 호출하고 STATUS_MORE_PROCESSING_REQUIRED 반환합니다. 이 상태 반환하면 I/O 관리자가 DupIRP2에서 추가 완료 처리를 시도할 수 없습니다. IRP가 스레드와 연결되지 않았기 때문에 완료 처리는 만든 드라이버로 끝나야 합니다.

하위 수준 드라이버 집합 중 하나가 미러 드라이버의 IRP를 성공적으로 완료하지 못하면 미러 드라이버의 IoCompletion 루틴에서 오류를 기록하고 적절한 미러된 데이터 복구를 시도해야 합니다. 자세한 내용은 로깅 오류를 참조하세요.