예제 I/O 요청 - 세부 정보

파일 개체를 여는 그림에서는 두 개의 I/O 스택 위치가 있는 IRP를 보여 주지만, 지정된 요청을 처리할 계층화된 드라이버 수에 따라 IRP에는 여러 I/O 스택 위치가 있을 수 있습니다.

다음 그림에서는 파일 개체 열기 그림의 드라이버가 I/O 지원 루틴(IoXxx 루틴)을 사용하여 읽기 또는 쓰기 요청에 대한 IRP를 처리하는 방법을 자세히 보여 줍니다.

계층화된 드라이버의 처리 irps를 보여 주는 다이어그램

  1. I/O 관리자는 하위 시스템의 읽기/쓰기 요청에 할당된 IRP를 사용하여 FSD(파일 시스템 드라이버)를 호출합니다. FSD는 IRP의 I/O 스택 위치에 액세스하여 수행해야 하는 작업을 결정합니다.

  2. FSD는 I/O 지원 루틴(IoAllocateIrp)을 한 번 이상 호출하여 추가 IRP를 할당하여 원래 요청을 더 작은 요청(둘 이상의 디바이스 드라이버에 대해)으로 분할할 수 있습니다. 하위 수준 드라이버에 대해 채워진 I/O 스택 위치가 0인 추가 IRP가 FSD로 반환됩니다. FSD는 재량에 따라 원래 IRP에서 다음 낮은 드라이버의 I/O 스택 위치를 설정하고 낮은 드라이버에 전달하여 이전 그림과 같이 추가 IRP를 할당하는 대신 원래 IRP를 다시 사용할 수 있습니다.

  3. 드라이버가 할당한 각 IRP에 대해 이전 그림의 FSD는 I/O 지원 루틴을 호출하여 FSD 제공 완료 루틴을 등록합니다. 완료 루틴에서 FSD는 낮은 드라이버가 요청을 충족하는지 여부를 결정하고 낮은 드라이버가 완료되었을 때 각 드라이버 할당 IRP를 해제할 수 있습니다. I/O 관리자는 드라이버 할당 IRP가 성공적으로 완료되었는지, 오류 상태 완료되었는지 또는 취소되었는지에 관계없이 FSD 제공 완료 루틴을 호출합니다. 상위 수준 드라이버는 할당한 모든 IRP를 해제하고 하위 수준 드라이버를 위해 자체적으로 설정합니다. I/O 관리자는 모든 드라이버가 완료된 후 할당하는 IRP를 해제합니다.

    다음으로 FSD는 I/O 지원 루틴(IoGetNextIrpStackLocation)을 호출하여 다음 하위 드라이버에 대한 요청을 설정하기 위해 다음 하위 수준 드라이버의 I/O 스택 위치에 액세스합니다. (이전 그림에서 다음 하위 드라이버는 가장 낮은 수준의 드라이버가 됩니다.) 그런 다음 FSD는 I/O 지원 루틴(IoCallDriver)을 호출하여 해당 IRP를 다음 하위 드라이버에 전달합니다.

  4. IRP를 사용하여 호출될 때 가장 낮은 수준의 드라이버는 I/O 스택 위치를 확인하여 대상 디바이스에서 수행해야 하는 작업( IRP_MJ_XXX 함수 코드로 표시됨)을 결정합니다. 대상 디바이스는 지정된 I/O 스택 위치에서 디바이스 개체로 표시되며 IRP와 함께 드라이버에 전달됩니다. 가장 낮은 수준의 드라이버는 I/O 관리자가 IRP를 IRP_MJ_XXX 작업 (여기서 는 IRP_MJ_READ 또는 IRP_MJ_WRITE)에 대해 정의한 진입점으로 라우팅하고 상위 수준 드라이버가 요청에 대한 다른 매개 변수의 유효성을 확인한다고 가정할 수 있습니다.

    상위 수준 드라이버가 없는 경우 가장 낮은 수준의 드라이버는 IRP_MJ_XXX 작업에 대한 입력 매개 변수가 유효한지 여부를 검사. 이 경우 드라이버는 일반적으로 I/O 지원 루틴을 호출하여 IRP에서 디바이스 작업이 보류 중임을 I/O 관리자에게 알리고 IRP를 큐에 넣거나 대상 디바이스에 액세스하는 다른 드라이버 제공 루틴(여기서는 실제 또는 논리 디바이스: 디스크 또는 디스크의 파티션)에 전달합니다.

  5. I/O 관리자는 드라이버가 이미 대상 디바이스에 대해 다른 IRP를 처리하고 있는 경우 IRP를 큐에 대기하고 반환하는지 여부를 결정합니다. 그렇지 않으면 I/O 관리자는 IRP를 디바이스에서 I/O 작업을 시작하는 드라이버 제공 루틴으로 라우팅합니다. (이 단계에서는 이전 그림의 드라이버와 I/O 관리자가 모두 컨트롤을 반환합니다.)

  6. 디바이스가 중단되면 드라이버의 ISR(인터럽트 서비스 루틴)은 디바이스의 중단을 중지하고 작업에 대한 필요한 컨텍스트를 저장하는 데 필요한 만큼만 작동합니다. 그런 다음 ISR은 IRP를 사용하여 I/O 지원 루틴(IoRequestDpc)을 호출하여 드라이버 제공 DPC(지연 프로시저 호출) 루틴을 큐에 대기하여 ISR보다 낮은 하드웨어 우선 순위로 요청된 작업을 완료합니다.

  7. 드라이버의 DPC가 제어를 받으면 컨텍스트( ISR의 IoRequestDpc 호출에 전달됨)를 사용하여 I/O 작업을 완료합니다. DPC는 지원 루틴을 호출하여 다음 IRP(있는 경우)를 큐에서 제거하고 해당 IRP를 디바이스에서 I/O 작업을 시작하는 드라이버 제공 루틴에 전달합니다(5단계 참조). 그런 다음 DPC는 IRP의 I/O 상태 블록에서 방금 완료된 작업에 대한 상태 설정하고 IoCompleteRequest를 사용하여 I/O 관리자에게 반환합니다.

  8. I/O 관리자는 IRP에서 가장 낮은 수준의 드라이버 I/O 스택 위치를 0으로 지정하고 FSD 할당 IRP를 사용하여 파일 시스템의 등록된 완료 루틴(3단계 참조)을 호출합니다. 이 완료 루틴은 I/O 상태 블록을 확인하여 요청을 다시 시도할지 또는 원래 요청에 대해 유지 관리되는 내부 상태를 업데이트할지 여부를 확인하고 드라이버 할당 IRP를 해제합니다. 파일 시스템은 I/O 상태 설정하고 원래 IRP를 완료할 수 있도록 하위 수준 드라이버에 보내는 모든 드라이버 할당 IRP에 대한 상태 정보를 수집할 수 있습니다. 파일 시스템이 원래 IRP를 완료하면 I/O 관리자는 I/O 작업의 원래 요청자(하위 시스템의 네이티브 함수)에 및 NTSTATUS 값을 반환합니다.

계층화된 드라이버의 처리 IRP 그림에 표시된 파일 시스템 드라이버와 마찬가지로 기존 드라이버 체인에 추가된 모든 새 드라이버는 다음을 모두 수행할 수 있습니다.

  • 자체 완성 루틴을 IRP로 설정합니다. IoCompletion 루틴은 I/O 상태 블록을 확인하여 낮은 드라이버가 IRP를 성공적으로 완료했는지, IRP를 취소했는지 또는 오류로 완료했는지 확인합니다. 완료 루틴은 IRP를 완료하기 전에 드라이버가 저장했을 수 있는 IRP 관련 상태를 업데이트하고, 드라이버가 할당했을 수 있는 작업별 리소스를 해제할 수도 있습니다. 또한 완료 루틴은 IRP 완료를 연기할 수 있으며(IRP에 더 많은 처리가 필요하다는 것을 I/O 관리자에게 알려서) IRP 완료를 허용하기 전에 다음 하위 수준 드라이버에 다른 요청을 보낼 수 있습니다.

  • 할당하는 IRP에서 다음 하위 수준 드라이버의 I/O 스택 위치를 설정하고 다음 하위 수준 드라이버에 요청을 보냅니다.

  • 각 IRP에서 다음으로 낮은 드라이버의 I/O 스택 위치를 설정하고 IoCallDriver를 호출하여 들어오는 요청을 낮은 드라이버에 전달합니다. (주 함수 코드 가 IRP_MJ_POWER IRP의 경우 드라이버는 PoCallDriver를 사용해야 합니다.)

드라이버에서 만든 각 디바이스 개체는 특정 드라이버가 I/O 요청을 수행하는 물리적, 논리적 또는 가상 디바이스를 나타냅니다. 디바이스 개체를 만들고 설정하는 방법에 대한 자세한 내용은 디바이스 개체 및 디바이스 스택을 참조하세요.

계층화된 드라이버의 처리 IRP 그림에서도 알 수 있듯이 대부분의 드라이버는 드라이버가 제공하는 시스템 정의 표준 루틴 집합을 통해 각 IRP를 단계적으로 처리하지만 체인의 다른 수준에 있는 드라이버는 반드시 표준 루틴이 다릅니다. 예를 들어 하위 수준 드라이버만 물리적 디바이스의 인터럽트를 처리하므로 가장 낮은 수준의 드라이버에만 인터럽트 기반 I/O 작업을 완료하는 ISR 및 DPC가 있습니다. 반면, 이러한 드라이버는 디바이스에서 인터럽트를 받을 때 I/O가 완료되었음을 알고 있으므로 완료 루틴이 필요하지 않습니다. 이 그림에서는 상위 수준 드라이버만 FSD와 같은 하나 이상의 완료 루틴을 갖습니다.