보류 중인 I/O 요청 적용

보류 중인 I/O 요청 적용 옵션은 IoCallDriver에 대한 드라이버의 호출에 응답하여 임의로 STATUS_PENDING을 반환합니다. 이 옵션은 IoCallDriver의 STATUS_PENDING 반환 값에 응답하는 드라이버의 논리를 테스트합니다.

이 옵션은 Windows Vista 이상의 운영 체제에서만 사용할 수 있습니다.

주의   드라이버 작동에 대해 자세히 알고 있지 않다면, 그리고 드라이버가 IoCallDriver에 대한 모든 호출에서 오는 STATUS_PENDING 반환 값을 처리하도록 설계되었음을 검증하지 않았다면 이 옵션을 사용하지 마세요. 모든 호출에서 오는 STATUS_PENDING을 처리하도록 설계되지 않은 드라이버에서 이 옵션을 실행하면 크래시, 메모리 손상, 디버그하거나 수정하기 어려울 수 있는 비정상적인 시스템 동작이 발생할 수 있습니다.

보류 중인 I/O 요청 적용을 사용하는 이유

드라이버 스택에서 더 높은 수준에 있는 드라이버는 더 낮은 수준에 있는 드라이버로 IRP를 전달하기 위해 IoCallDriver를 호출합니다. IRP를 받는 낮은 수준의 드라이버에 있는 드라이버 디스패치 루틴은 IRP를 즉시 완료할 수도 있고, STATUS_PENDING을 반환하고 IRP를 나중에 완료할 수도 있습니다.

일반적으로 호출자는 두 가지 결과를 모두 처리할 수 있도록 준비해야 합니다. 그러나 대부분의 디스패치 루틴은 IRP를 즉시 처리하므로 호출자의 STATUS_PENDING 논리가 종종 실행되지 않고 심각한 논리 오류가 감지될 수 있습니다. 보류 중인 I/O 요청 적용 옵션은 IoCallDriver에 대한 호출을 가로채고, 호출 드라이버에서 가끔 사용하는 논리를 테스트할 수 있도록 STATUS_PENDING을 반환합니다.

보류 중인 I/O 요청 적용을 사용하는 시기

이 테스트를 실행하기 전에 드라이버의 설계와 소스 코드를 검토하고, 드라이버가 모든 IoCallDriver 호출에서 오는 STATUS_PENDING을 처리하도록 설계되었는지 확인하세요.

다수의 드라이버가 IoCallDriver에 대한 모든 호출에서 STATUS_PENDING을 처리하도록 설계되지 않았습니다. 그러한 드라이버는 IRP를 즉시 완료할 수 있는 잘 알려진 특정 드라이버로 IRP를 전송합니다. 처리할 수 없는 드라이버로 STATUS_PENDING을 전송하면 드라이버 및 시스템 크래시와 메모리 손상이 발생할 수 있습니다.

드라이버에서 STATUS_PENDING을 처리하는 방법

IoCallDriver를 호출하는 높은 수준의 드라이버는 다음과 같이 STATUS_PENDING 반환 값을 처리해야 합니다.

  • IoCallDriver를 호출하기 전에 드라이버는 IoBuildSynchronousFsdRequest를 호출하여 IRP의 동기 처리를 준비해야 합니다.

  • IoCallDriver가 STATUS_PENDING을 반환하면 드라이버는 지정된 이벤트에 대해 KeWaitForSingleObject를 호출하여 IRP의 완료를 기다려야 합니다.

  • 드라이버는 I/O 관리자가 이벤트 신호를 보내기 전에 IRP가 비워질 것으로 예상합니다.

  • 호출자는 IoCallDriver를 호출한 후 IRP를 참조할 수 없습니다.

보류 중인 I/O 요청 적용에서 감지하는 오류

보류 중인 I/O 요청 적용 옵션은 IoCallDriver를 호출하고 STATUS_PENDING 반환 값을 받는 드라이버에서 다음 오류를 감지합니다.

  • 드라이버가 IoBuildSynchronousFsdRequest를 호출하여 동기 처리를 준비하지 못합니다.

  • 드라이버가 KeWaitForSingleObject를 호출하지 않습니다.

  • 드라이버가 IoCallDriver를 호출한 후 IRP 구조에서 값을 참조합니다. 높은 수준의 드라이버는 IoCallDriver를 호출한 후, 완료 루틴을 설정하고 모든 낮은 수준의 드라이버에서 IRP를 완료한 경우에만 IRP에 액세스할 수 있습니다. IRP가 비워지면 드라이버 크래시가 발생합니다.

  • 드라이버가 관련된 함수를 잘못 호출합니다. 예를 들면 드라이버가 KeWaitForSingleObject를 호출하고, 포인터를 이벤트 개체에 전달하는 대신 핸들을 이벤트(Object 매개 변수로서)에 전달합니다.

  • 드라이버가 잘못된 이벤트를 기다립니다. 예를 들면 드라이버가 IoSetCompletionRoutine을 호출하고, IRP가 완료될 때 I/O 관리자에 의해 신호가 전송되는 IRP 이벤트를 기다리는 대신 자체 완료 루틴에 의해 신호가 전송되는 내부 이벤트를 기다립니다.

Windows 7에 새로 추가된 보류 중인 I/O 요청 적용 변경

Windows 7부터 보류 중인 I/O 요청 적용 옵션은 검증된 드라이버에서 STATUS_PENDING 코드를 강제로 실행할 때 더욱 효과적입니다. 이전 Windows 버전에서는 해당 IRP에 대한 첫 번째 IoCompleteRequest가 실행될 경우에만 드라이버 검증 도구가 IRP 완료를 강제로 지연시켰습니다. 즉, 동일한 장치 스택에서 수행되는 Driver2 동작으로 인해 Driver1 검증의 유효성이 감소할 수 있습니다. Driver2는 디스패치 루틴에서 Driver1로 돌아가기 전에 동기적으로 완료를 기다릴 수 있습니다. IRP 완료 강제 지연은 I/O 요청이 다시 완료 경로의 검증된 드라이버로 풀리기 전에 발생합니다. 즉, 검증된 드라이버의 STATUS_PENDING 코드 경로가 실제로 실행되고 검증된 드라이버가 완료 시 지연을 인식합니다.

이 옵션 활성화

보류 중인 I/O 요청 적용을 활성화하려면 I/O 검증도 활성화해야 합니다. 드라이버 검증 도구 관리자 또는 Verifier.exe 명령줄을 사용하여 하나 이상의 드라이버에 대해 보류 중인 I/O 요청 적용 옵션을 활성화할 수 있습니다. 자세한 내용은 드라이버 검증 도구 옵션 선택을 참조하세요.

보류 중인 I/O 요청 적용 옵션은 Windows Vista 이상에서만 지원됩니다.

  • 명령줄에서

    보류 중인 I/O 요청 적용을 활성화하려면 0x210의 플래그 값을 사용하거나 플래그 값에 0x210을 추가하세요. 이 값은 I/O 검증(0x10)을 활성화한 후 보류 중인 I/O 요청 적용(0x200)을 활성화합니다.

    예를 들면 다음과 같습니다.

    
    verifier /flags 0x210 /driver MyDriver.sys
    
    

    다음에 부팅하면 옵션이 활성화됩니다.

    사용자가 보류 중인 I/O 요청 적용(verifier /flags 0x200)만 활성화하려고 하면 드라이버 검증 도구는 자동으로 보류 중인 I/O 요청 적용(0x200) 및 I/O 검증을 모두 활성화합니다.

    또한 명령줄에 /volatile 매개 변수를 추가하면 컴퓨터를 다시 부팅하지 않고도 보류 중인 I/O 요청 적용을 활성화 및 비활성화할 수 있습니다. 예를 들면 다음과 같습니다.

    
    verifier /volatile /flags 0x210 /adddriver MyDriver.sys
    
    

    이 설정은 바로 적용되지만 컴퓨터를 종료하거나 다시 부팅하면 손실됩니다. 자세한 내용은 일시적 설정 사용을 참조하세요.

  • 드라이버 검증 도구 관리자 사용
    1. 드라이버 검증 도구 관리자를 시작합니다. 명령 프롬프트 창에 Verifier를 입력합니다.
    2. 사용자 지정 설정 만들기(코드 개발자용)를 선택하고 다음을 클릭합니다.
    3. 전체 목록에서 개별 설정 선택을 선택합니다.
    4. I/O 검증 및 보류 중인 I/O 요청 적용을 선택합니다.

    사용자가 보류 중인 I/O 요청 적용만 선택하면, 드라이버 검증 도구 관리자는 I/O 검증도 필요하므로 함께 활성화해줄 수 있다는 내용의 메시지를 표시합니다.

결과 보기

보류 중인 I/O 요청 적용 테스트의 결과를 보려면 0x40의 플래그 값으로 !verifier 디버거 확장을 사용하세요.

!verifier에 대한 자세한 내용은 Windows용 디버깅 도구 설명서의 !verifier 항목을 참조하세요.

보류 중인 I/O 요청 적용 테스트 결과 테스트 컴퓨터가 크래시되면 !verifier 40 명령을 사용하여 원인을 찾을 수 있습니다. 현재 스택 추적에서, 드라이버가 최근에 사용한 IRP의 주소를 찾습니다. 예를 들어, 스레드에 대한 스택 프레임을 표시하는 kP 명령을 사용하는 경우 현재 스택 추적의 함수 매개 변수 중에서 IRP 주소를 찾을 수 있습니다. 그런 다음 !verifier 40을 실행하고 IRP의 주소를 찾습니다. 가장 최근의 보류 적용 스택 추적은 맨 위에 표시됩니다.

예를 들어, Pci.sys의 다음 스택 추적은 보류 중인 I/O 요청 적용에 대한 응답을 보여 줍니다. 테스트 결과 Pci.sys 논리의 오류는 표시되지 않습니다.


kd> !verifier 40
Size of the log is is 0x40
========================================================
IRP: 8f84ef00 - forced pending from stack trace:

     817b21e4 nt!IovpLocalCompletionRoutine+0xb2
     81422478 nt!IopfCompleteRequest+0x15c
     817b2838 nt!IovCompleteRequest+0x9c
     84d747df acpi!ACPIBusIrpDeviceUsageNotification+0xf5
     84d2d36c acpi!ACPIDispatchIrp+0xe8
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     817c6a9d nt!ViFilterDispatchPnp+0xe9
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     84fed489 pci!PciCallDownIrpStack+0xbf
     84fde1cb pci!PciDispatchPnpPower+0xdf
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     817c6a9d nt!ViFilterDispatchPnp+0xe9
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     84ff2ff5 pci!PciSendPnpIrp+0xbd
 84fec820 pci!PciDevice_DeviceUsageNotification+0x6e
     84fde1f8 pci!PciDispatchPnpPower+0x10c
 817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     84d76ce2 acpi!ACPIFilterIrpDeviceUsageNotification+0x96
     84d2d36c acpi!ACPIDispatchIrp+0xe8
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c
     84f7f16c PCIIDEX!PortWdmForwardIrpSynchronous+0x8e
     84f7b2b3 PCIIDEX!GenPnpFdoUsageNotification+0xcb
     84f7d301 PCIIDEX!PciIdeDispatchPnp+0x45
     817b258f nt!IovCallDriver+0x19d
     8142218e nt!IofCallDriver+0x1c

스택 추적은 Acpi.sys가 IRP 8f84ef00을 완료하려고 시도했음을 보여 줍니다. 드라이버 검증 도구는 연기된 완료를 적용하므로, Acpi.syspci!PciCallDownIrpStack에 STATUS_PENDING을 반환합니다. 이 호출로 인해 크래시가 발생하면 드라이버 소유자는 소스 코드에서 pci!PciCallDownIrpStack을 검토하고 STATUS_PENDING을 적절히 처리할 수 있도록 수정해야 합니다.

 

 

표시:
© 2014 Microsoft