다음을 통해 공유


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

가장 낮은 수준의 물리적 드라이버에는 상위 수준 드라이버가 필요하지 않은 특정 표준 루틴이 있습니다. 최저 수준 드라이버에 대한 표준 루틴 집합도 다음 기준에 따라 달라집니다.

  • 각 드라이버가 제어하는 디바이스의 특성

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

  • 개별 드라이버의 디자인

표준 드라이버 루틴의 역할을 설명하기 위해 다음 그림에서는 가장 낮은 수준의 대용량 스토리지 디바이스 드라이버에서 처리할 때 샘플 IRP가 취할 수 있는 경로를 보여 줍니다. 그림의 드라이버에는 다음과 같은 특성이 있습니다.

  • 디바이스는 각 I/O 작업이 끝날 때 인터럽트 생성되므로 이 드라이버에는 ISR 및 DpcForIsr 루틴이 있습니다.

  • 드라이버에는 IRP에 대한 내부 큐를 설정하고 자체 큐를 관리하는 대신 StartIo 루틴이 있습니다.

  • 드라이버는 시스템 DMA를 사용하므로 직접 I/O에 대한 디바이스 개체의 플래그 를 설정하고 AdapterControl 루틴이 있습니다.

가장 낮은 수준의 드라이버 루틴을 통한 irp 경로를 보여 주는 다이어그램

이 그림과 같이 I/O 관리자는 IRP를 만들고 지정된 주 함수 코드에 대한 드라이버의 디스패치 루틴으로 보냅니다. 함수 코드가 IRP_MJ_READ 또는 IRP_MJ_WRITE 경우 디스패치 루틴은 DDDispatchReadWrite입니다.

IoGetCurrentIrpStackLocation 호출

IRP 매개 변수가 필요한 모든 드라이버 루틴은 IoGetCurrentIrpStackLocation 을 호출하여 드라이버의 I/O 스택 위치를 가져와야 합니다. 이러한 루틴에는 둘 이상의 주요 I/O 함수 코드(IRP_MJ_*XXX)를 처리하거나, 부 함수(IRP_MN_XXX)를 지원하는 함수를 처리하거나, IRP를 처리하는 다른 모든 드라이버 루틴과 함께 디바이스 I/O 제어 요청(*IRP_MJ_DEVICE_CONTROL 및/또는 IRP_MJ_INTERNAL_DEVICE_CONTROL)을 처리하는 디스패치 루틴이 포함됩니다.

이 드라이버의 I/O 스택 위치는 가장 낮으며, 셰이딩된 것으로 표시된 상위 수준의 드라이버 I/O 스택 위치는 무기한으로 표시됩니다. 간단히 하기 위해 DispatchReadWrite, StartIo, AdapterControlDpcForIsr 루틴에서 IoGetCurrentIrpStackLocation에 대한 호출은 이전 그림에 표시되지 않습니다.

IoMarkIrpPending 및 IoStartPacket 호출

샘플 드라이버는 디스패치 루틴에서 IRP를 완료하지 않고 대신 StartIo 루틴에서 IRP를 처리합니다. 이렇게 하기 전에 디스패치 루틴은 IoMarkIrpPending을 호출하여 IRP가 아직 완료되지 않았음을 나타냅니다. 그런 다음 IoStartPacket 을 호출하여 드라이버의 StartIo 루틴에서 추가 처리를 위해 IRP를 큐에 대기합니다. 또한 디스패치 루틴은 STATUS_PENDING NTSTATUS 값을 반환합니다.

다음 그림에서는 IoStartPacket에 대한 호출을 보여 줍니다.

iostartpacket에 대한 호출을 보여 주는 다이어그램

드라이버가 디바이스에서 다른 IRP를 처리하는 중이면 IoStartPacket 은 디바이스 개체와 연결된 디바이스 큐에 IRP를 삽입합니다. 드라이버는 필요에 따라 값을 IoStartPacket 에 매개 변수로 제공하여 디바이스 큐의 IRP에 드라이버 결정 순서를 적용할 수 있습니다.

드라이버가 사용 중이 아니고 디바이스 큐가 비어 있는 경우 I/O 관리자는 즉시 StartIo 루틴을 호출하여 입력 IRP를 전달합니다.

대용량 스토리지 디바이스의 경우 가장 낮은 수준의 드라이버는 다음 두 가지 이유로 IoStartPacket을 호출할 때 Cancel 루틴을 제공할 필요가 없습니다.

  1. 이러한 드라이버 위에 계층화된 파일 시스템은 일반적으로 파일 I/O 요청의 취소를 처리합니다.

  2. 대용량 스토리지 디바이스 드라이버는 IRP를 신속하게 처리합니다.

일반적으로 계층화된 드라이버 체인에서 가장 높은 수준의 드라이버는 IRP 취소를 처리합니다.

AllocateAdapterChannel 및 MapTransfer 호출

가장 낮은 수준의 드라이버 루틴을 통한 IRP 경로를 보여 주는 그림에 표시된 StartIo 루틴이 단일 DMA 작업으로 전송 요청을 수행할 수 있다고 가정하면 StartIo 루틴은 드라이버의 AdapterControl 루틴 및 IRP의 진입점을 사용하여 AllocateAdapterChannel을 호출합니다.

시스템 DMA 컨트롤러를 사용할 수 있는 경우 I/O 관리자는 드라이버의 AdapterControl 루틴을 호출하여 전송 작업을 설정합니다. AdapterControl 루틴은 MapTransfer를 호출하여 시스템 DMA 컨트롤러를 설정합니다. 그런 다음 드라이버는 DMA 작업을 위해 디바이스를 프로그래밍하고 를 반환합니다. (DMA 및 어댑터 개체 사용에 대한 자세한 내용은 입력/출력 기술을 참조하세요.)

드라이버의 ISR에서 IoRequestDpc 호출

디바이스가 인터럽트하여 전송 작업이 완료되었음을 나타내면 드라이버의 ISR은 디바이스가 인터럽트를 생성하지 못하도록 중지하고 최하위 수준의 드라이버 루틴을 통한 IRP 경로를 보여 주는 그림과 같이 IoRequestDpc를 호출합니다.

이 호출은 드라이버의 DpcForIsr 루틴을 큐에 대기하여 IRQL(낮은 하드웨어 우선 순위)에서 가능한 한 많은 전송 작업을 완료합니다.

IoStartNextPacket 및 IoCompleteRequest 호출

DpcForIsr 루틴이 전송 처리를 완료하면 드라이버의 StartIo 루틴이 큐에 대기 중인 경우 디바이스 큐의 다음 IRP를 사용하여 호출되도록 IoStartNextPacket을 즉시 호출합니다. 또한 DpcForIsr 루틴은 방금 완료된 IRP의 I/O 상태 블록을 설정한 다음 IRP에 대해 IoCompleteRequest를 호출합니다.

다음 그림에서는 IoStartNextPacketIoCompleteRequest에 대한 이 드라이버의 호출을 보여 줍니다.

iostartnextpacket 및 iocompleterequest를 호출합니다.

드라이버는 IoStartNextPacket 또는 IoStartNextPacketByKey 를 호출하여 IoCompleteRequest를 호출하기 전에 가능한 한 빨리 다음 요청된 I/O 작업을 시작해야 합니다.

디바이스에 대한 IRP가 큐에 대기 중인 경우 IoStartNextPacketKeRemoveDeviceQueue 를 호출하여 큐에서 다음 IRP를 제거합니다. 그런 다음 I/O 관리자는 드라이버의 StartIo 루틴을 호출하여 큐에서 해제된 IRP를 전달합니다. 현재 디바이스 큐에 IRP가 없는 경우 IoStartNextPacket 은 호출자에게만 반환됩니다.

IRP에서 I/O 상태 블록 설정

모든 최저 수준 드라이버는 IoCompleteRequest를 호출하기 전에 IRP의 I/O 상태 블록을 설정해야 합니다. (이전 그림에서 두 번째 음영 영역은 상태 블록을 나타냅니다.) I/O 상태 블록은 상위 수준 드라이버에 정보를 제공하고 궁극적으로 I/O 작업의 원래 요청자에게 정보를 제공합니다. 이전 그림의 드라이버 위에 계층화된 상위 수준 드라이버는 이 드라이버가 설정한 I/O 상태 블록을 읽는 IoCompletion 루틴을 설정했을 수 있습니다. 상위 수준 드라이버는 일반적으로 IRP를 다시 시도하지 않는 한 디바이스 드라이버에서 완료된 IRP에서 I/O 상태 블록을 수정하지 않습니다. 이 경우 I/O 상태 블록을 다시 초기화합니다.

IRP를 다음 하위 드라이버로 보내지 않고 완료하는 모든 상위 수준 드라이버도 IoCompleteRequest를 호출하기 전에 해당 IRP에서 I/O 상태 블록을 설정해야 합니다. 전반적인 I/O 처리량을 높이려면 상위 수준 드라이버가 각 IRP의 자체 I/O 스택 위치에 매개 변수를 검사 매개 변수가 유효하지 않은 경우 I/O 상태 블록을 설정하고 요청 자체를 완료해야 합니다. 가능하면 드라이버는 체인의 낮은 드라이버에 잘못된 요청을 전달하지 않아야 합니다.

이전 그림의 전송 작업이 성공했다고 가정하면 가장 낮은 수준의 드라이버 루틴을 통해 IRP 경로를 보여 주는 그림에 표시된 DpcForIsr 루틴은 상태의 STATUS_SUCCESS 설정하고 IRP의 I/O 상태 블록에 대한 정보에서 전송된 바이트 수를 설정합니다.

대부분의 표준 드라이버 루틴은 NTSTATUS 형식 값도 반환합니다. STATUS_SUCCESS 같은 NTSTATUS 상수에 대한 자세한 내용은 로깅 오류를 참조하세요.