I/O 작업의 진행률 보장

시스템의 페이징 디바이스에 대한 스토리지 드라이버와 같은 일부 드라이버는 중요한 시스템 데이터 손실을 방지하기 위해 지원되는 I/O 작업 중 일부 이상을 실패 없이 수행해야 합니다. 드라이버 오류의 한 가지 잠재적 원인은 메모리 부족 상황입니다. 프레임워크 또는 드라이버가 I/O 요청을 처리하기에 충분한 메모리를 할당할 수 없는 경우 오류 상태 값으로 완료 하여 I/O 요청을 실패해야 할 수 있습니다.

버전 1.9 이전의 KMDF 버전에서 I/O 관리자가 드라이버에 보낸 IRP(I/O 요청 패킷)에 대한 프레임워크 요청 개체를 할당할 수 없는 경우 프레임워크는 항상 I/O 요청에 실패합니다. 메모리 부족 상황에서 드라이버가 I/O 요청을 처리하는 기능을 제공하기 위해 프레임워크 버전 1.9 이상은 I/O 큐에 대해 보장된 진행률 기능을 제공합니다.

이 기능을 사용하면 프레임워크와 드라이버가 각각 요청 개체 및 요청 관련 드라이버 컨텍스트 버퍼 집합에 대한 메모리를 미리 할당할 수 있습니다. 프레임워크와 드라이버는 시스템 메모리 양이 부족한 경우에만 미리 할당된 이 메모리를 사용합니다.

앞으로 진행이 보장되는 기능

I/O 큐에 대해 프레임워크의 보장된 진행률을 사용하여 드라이버는 다음을 수행할 수 있습니다.

  • 메모리가 부족한 상황에서 특정 I/O 큐와 함께 사용할 요청 개체 집합을 미리 할당하도록 프레임워크에 요청합니다.

  • 드라이버가 메모리 부족 상황에서 프레임워크에서 미리 할당된 요청 개체를 수신할 때 사용할 수 있는 요청별 리소스를 미리 할당하는 콜백 함수를 제공합니다.

  • 메모리 부족 상황이 감지 되지 않은 경우 I/O 요청에 대한 드라이버별 리소스를 할당하는 또 다른 콜백 함수를 제공합니다. 메모리 부족 상황으로 인해 이 콜백 함수의 할당이 실패하면 프레임워크가 미리 할당된 요청 개체 중 하나를 사용해야 하는지 여부를 나타낼 수 있습니다.

  • 미리 할당된 요청 개체를 사용해야 하는 I/O 요청을 지정합니다. 옵션에는 모든 IRP에 대해 미리 할당된 개체를 사용하거나, 페이징 I/O 작업이 진행 중인 경우에만 사용하거나, 추가 드라이버 콜백 함수가 각 IRP를 검사하여 미리 할당된 개체를 사용할지 여부를 확인하는 것이 포함됩니다.

드라이버가 하나 이상의 I/O 큐에 대해 보장된 정방향 진행률을 구현하는 경우 드라이버는 메모리 부족 상황에서 I/O 요청을 성공적으로 처리 할 수 있습니다. WdfDeviceConfigureRequestDispatching을 호출하여 디바이스의 기본 I/O 큐 및 드라이버가 구성하는 모든 I/O 큐에 대해 보장된 정방향 진행률을 구현할 수 있습니다.

프레임워크의 보장된 앞으로 진행률 기능은 드라이버와 드라이버의 I/O 대상이 모두 보장된 전진 진행률을 구현하는 경우에만 드라이버에 작동합니다. 즉, 드라이버가 디바이스에 대해 보장된 앞으로 진행률을 구현하는 경우 디바이스의 드라이버 스택에 있는 모든 하위 수준 드라이버도 보장된 앞으로 진행률을 구현해야 합니다.

I/O 큐에 대해 보장된 전달 진행률 사용

I/O 큐에 대해 보장된 정방향 진행을 사용하도록 설정하기 위해 드라이버는 WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY 구조를 초기화한 다음 WdfIoQueueAssignForwardProgressPolicy 메서드를 호출합니다. 드라이버가 WdfDeviceConfigureRequestDispatching을 호출하여 I/O 큐를 구성하는 경우 WdfIoQueueAssignForwardProgressPolicy를 호출하기 전에 이 작업을 수행해야 합니다.

드라이버가 WdfIoQueueAssignForwardProgressPolicy를 호출하는 경우 다음 세 가지 이벤트 콜백 함수를 지정할 수 있으며, 모두 선택 사항입니다.

EvtIoAllocateResourcesForReservedRequest
드라이버의 EvtIoAllocateResourcesForReservedRequest 콜백 함수는 프레임워크가 메모리 부족 상황에 대해 예약하는 요청 개체에 대한 요청별 리소스를 할당하고 저장합니다.

프레임워크는 예약된 요청 개체를 만들 때마다 이 콜백 함수를 호출합니다. 드라이버는 일반적으로 예약된 요청 개체의 컨텍스트 공간을 사용하여 하나의 I/O 요청에 대한 요청별 리소스를 할당해야 합니다.

EvtIoAllocateRequestResources
드라이버의 EvtIoAllocateRequestResources 콜백 함수는 즉시 사용할 수 있도록 요청별 리소스를 할당합니다. 프레임워크가 IRP를 수신하고 IRP에 대한 요청 개체를 만든 직후 호출됩니다.

콜백 함수의 리소스 할당 시도가 실패하면 콜백 함수는 오류 상태 값을 반환합니다. 그런 다음 프레임워크는 새로 만든 요청 개체를 삭제하고 예약된 요청 개체 중 하나를 사용합니다. 드라이버의 요청 처리기는EvtIoAllocateRequestResources 콜백 함수가 이전에 할당한 요청별 리소스를 사용합니다.

EvtIoWdmIrpForForwardProgress
드라이버의 EvtIoWdmIrpForForwardProgress 콜백 함수는 IRP를 검사하고 IRP에 예약된 요청 개체를 사용할지 또는 오류 상태 값으로 완료하여 I/O 요청을 실패할지 프레임워크에 지시합니다.

프레임워크는 프레임워크가 새 요청 개체를 만들 수 없고 드라이버의 WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY 구조에서 플래그를 설정하여 메모리 부족 상황에서 드라이버가 IRP를 검사할 것을 표시한 경우에만 이 콜백 함수를 호출합니다. 즉, 드라이버는 각 IRP를 평가하고 메모리 부족 상황에서도 처리해야 하는 IRP인지 여부를 결정할 수 있습니다.

드라이버가 WdfIoQueueAssignForwardProgressPolicy를 호출할 때 프레임워크가 메모리 부족 상황에 대해 미리 할당하려는 예약된 요청 개체의 수도 지정합니다. 디바이스 및 드라이버에 적합한 요청 개체 수를 선택할 수 있습니다. 성능 저하를 방지하기 위해 드라이버는 일반적으로 드라이버와 디바이스가 병렬로 처리할 수 있는 I/O 요청 수와 일치하는 숫자를 지정해야 합니다.

그러나 드라이버의 WdfIoQueueAssignForwardProgressPolicy해당 EvtIoAllocateResourcesForReservedRequest 콜백 함수가 너무 많은 예약된 요청 개체 또는 너무 많은 요청 관련 리소스 메모리를 미리 할당하는 경우 드라이버는 실제로 처리하려는 메모리 부족 상황에 기여할 수 있습니다. 드라이버 및 디바이스의 성능을 테스트하고 메모리가 부족한 시뮬레이션을 포함하여 선택할 수 있는 가장 좋은 숫자를 결정해야 합니다.

WdfIoQueueAssignForwardProgressPolicy가 반환되기 전에 프레임워크는 드라이버가 지정한 요청 개체 수를 만들고 예약합니다. 요청 개체를 예약할 때마다 프레임워크는 드라이버의 EvtIoAllocateResourcesForReservedRequest 콜백 함수를 즉시 호출하여 프레임워크가 실제로 예약된 요청 개체를 사용하는 경우 드라이버가 요청별 리소스를 할당하고 저장할 수 있도록 합니다.

드라이버의 요청 처리기 중 하나가 I/O 큐에서 I/O 요청을 받으면 WdfRequestIsReserved 메서드를 호출하여 요청 개체가 메모리 부족 상황에 대해 프레임워크가 미리 할당한 개체인지 여부를 확인할 수 있습니다. 이 메서드가 TRUE를 반환하는 경우 드라이버는 EvtIoAllocateResourcesForReservedRequest 콜백 함수가 예약한 리소스를 사용해야 합니다.

프레임워크에서 예약된 요청 개체 중 하나를 사용하는 경우 드라이버가 요청을 완료한 후 개체를 예약된 개체 집합으로 반환합니다. 프레임워크는 요청 개체와 드라이버가 WdfDeviceInitSetRequestAttributes 또는 WdfObjectAllocateContext를 호출하여 만든 컨텍스트 공간을 저장하여 메모리 부족 상황이 발생할 경우 다시 사용합니다.

프레임워크 및 드라이버 지원에서 진행 상황을 보장하는 방법

다음은 드라이버 및 프레임워크가 I/O 큐에 대해 보장된 진행률을 지원하기 위해 수행하는 단계입니다.

  1. 드라이버는 WdfIoQueueAssignForwardProgressPolicy를 호출합니다.

    이에 대한 응답으로 프레임워크는 드라이버가 지정하는 요청 개체 수를 할당하고 저장합니다. 이전에 WdfDeviceInitSetRequestAttributes라고 하는 드라이버의 경우 각 할당에는 WdfDeviceInitSetRequestAttributes 가 지정한 컨텍스트 공간이 포함됩니다.

    또한 드라이버가 EvtIoAllocateResourcesForReservedRequest 콜백 함수를 제공한 경우 프레임워크는 요청 개체를 할당하고 저장할 때마다 콜백 함수를 호출합니다.

  2. 프레임워크는 I/O 관리자가 드라이버에 보내는 IRP(I/O 요청 패킷)를 받습니다.

    프레임워크는 IRP에 대한 요청 개체를 할당하려고 시도합니다. 드라이버가 요청 유형에 대해 만든 I/O 큐가 보장된 진행률을 지원하는 경우 다음 단계는 할당의 성공 또는 실패 여부에 따라 달라집니다.

    • 요청 개체 할당이 성공합니다.

      드라이버가 EvtIoAllocateRequestResources 콜백 함수를 제공한 경우 프레임워크는 이를 호출합니다. 콜백 함수가 STATUS_SUCCESS 반환하는 경우 프레임워크는 I/O 큐에 요청을 추가합니다. 콜백 함수가 오류 상태 값을 반환하는 경우 프레임워크는 방금 만든 요청 개체를 삭제하고 미리 할당된 요청 개체 중 하나를 사용합니다. 드라이버의 요청 처리기가 요청 개체를 받으면 요청 개체가 미리 할당되었는지 여부와 드라이버의 미리 할당된 리소스를 사용해야 하는지 여부를 결정합니다.

      드라이버가 EvtIoAllocateRequestResources 콜백 함수를 제공하지 않은 경우 프레임워크는 드라이버가 보장된 진행률을 사용하도록 설정하지 않은 것처럼 I/O 큐에 요청을 추가합니다.

    • 요청 개체 할당이 실패합니다.

      프레임워크가 다음에 수행하는 일은 드라이버가 WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY 구조체의 ForwardProgressReservedPolicy 멤버에 제공한 값에 따라 달라집니다. 이 멤버는 예약된 요청을 사용해야 하는 경우 프레임워크에 알릴 수 있습니다. I/O 요청이 페이징 I/O 작업인 경우에만 또는 EvtIoWdmIrpForForwardProgress 콜백 함수가 예약된 요청을 사용해야 한다고 나타내는 경우에만 프레임워크에 알릴 수 있습니다.

    모든 경우에 드라이버의 요청 처리기는 WdfRequestIsReserved 를 호출하여 프레임워크가 예약된 요청 개체를 사용했는지 여부를 확인할 수 있습니다. 이 경우 드라이버는 EvtIoAllocateResourcesForReservedRequest 콜백 함수가 할당한 요청 리소스를 사용해야 합니다.

보장된 진행률 시나리오

시스템의 페이징 파일을 포함할 수 있는 스토리지 디바이스에 대한 드라이버를 작성하고 있습니다. 페이징 파일의 읽기 작업과 페이징 파일에 대한 쓰기 작업이 성공하는 것이 중요합니다.

읽기 및 쓰기 작업을 위한 별도의 I/O 큐를 만들고 이 두 I/O 큐에 대해 보장된 정방향 진행을 사용하도록 설정하기로 결정했습니다. 앞으로 진행을 보장하지 않고 다른 모든 요청 유형에 대해 세 번째 I/O 큐를 만들기로 결정합니다.

드라이버 스택 및 디바이스는 4개의 쓰기 작업을 병렬로 처리할 수 있으므로 WdfIoQueueAssignForwardProgressPolicy를 호출하기 전에 WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY 구조체의 TotalForwardProgressRequests 멤버를 4로 설정합니다.

드라이버의 디바이스가 페이징 디바이스인 경우에만 진행률을 보장하는 것이 중요하다고 판단하여 드라이버가 WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY 구조의 ForwardProgressReservedPolicy 멤버를 WdfIoForwardProgressReservedPolicyPagingIO로 설정합니다.

드라이버에는 각 읽기 요청 및 각 쓰기 요청에 대해 프레임워크 메모리 개체가 필요하므로 드라이버가 메모리 부족 상황에서 WdfIoTargetFormatRequestForReadWdfIoTargetFormatRequestForWrite 호출에 사용할 일부 메모리 개체를 미리 할당해야 한다고 결정합니다.

따라서 드라이버는 읽기 큐에 대한 EvtIoAllocateResourcesForReservedRequest 콜백 함수와 쓰기 큐에 대한 다른 콜백 함수를 제공합니다. 프레임워크가 이러한 콜백 함수 중 하나를 호출할 때마다 콜백 함수는 WdfMemoryCreate 를 호출하고 메모리 부족 상황에 대해 반환된 개체 핸들을 저장합니다. 콜백 함수는 미리 할당된 요청 개체에 대한 핸들을 수신하므로 메모리 개체를 요청 개체에 부모로 지정할 수 있습니다. (DMA 디바이스용 드라이버는 프레임워크 DMA 개체를 미리 할당할 수도 있습니다.)

읽기 및 쓰기 큐에 대한 요청 처리기는 수신된 각 요청 개체가 메모리 부족 상황에서 프레임워크가 예약한 개체인지 여부를 결정해야 합니다. 요청 처리기는 WdfRequestIsReserved를 호출하거나 요청 개체 핸들을 이전에 받은 EvtIoAllocateResourcesForReservedRequest 콜백 함수와 비교할 수 있습니다.

또한 드라이버는 읽기 큐에 대한 EvtIoAllocateRequestResources 콜백 함수와 쓰기 큐에 대한 콜백 함수를 제공합니다. 프레임워크는 I/O 관리자로부터 읽기 또는 쓰기 요청을 받고 요청 개체를 성공적으로 만들 때 이러한 콜백 함수 중 하나를 호출합니다. 이러한 각 콜백 함수는 WdfMemoryCreate 를 호출하여 요청에 대한 메모리 개체를 할당합니다. 할당이 실패하면 콜백 함수는 오류 상태 값을 반환하여 메모리 부족 상황이 방금 발생했음을 프레임워크에 알립니다. 오류 반환 값을 검색하는 프레임워크는 방금 만든 요청 개체를 삭제하고 미리 할당된 개체 중 하나를 사용합니다.

이 드라이버는 프레임워크가 I/O 큐에 추가하기 전에 개별 읽기 또는 쓰기 IRP를 검사할 필요가 없으므로 EvtIoWdmIrpForForWardProgress 콜백 함수를 제공하지 않습니다.

드라이버가 디바이스에 대해 보장된 앞으로 진행률을 구현하는 경우 디바이스의 드라이버 스택에 있는 모든 하위 수준 드라이버도 보장된 앞으로 진행률을 구현해야 합니다.