보류 중인 I/O 요청 강제 적용
보류 중인 I/O 요청 강제 옵션은 IoCallDriver에 대한 드라이버 호출에 대한 응답으로 STATUS_PENDING 임의로 반환합니다. 이 옵션은 IoCallDriver의 STATUS_PENDING 반환 값에 응답하기 위한 드라이버의 논리를 테스트합니다.
이 옵션은 Windows Vista 이상 버전의 Windows 운영 체제에서만 지원됩니다.
주의 드라이버의 작동에 대한 자세한 지식이 있고 드라이버가 IoCallDriver에 대한 모든 호출에서 STATUS_PENDING 반환 값을 처리하도록 설계되어 있는지 확인하지 않는 한 드라이버에서 이 옵션을 사용하지 마세요. 모든 호출에서 STATUS_PENDING 처리하도록 설계되지 않은 드라이버에서 이 옵션을 실행하면 크래시, 메모리 손상 및 디버그 또는 수정이 어려울 수 있는 비정상적인 시스템 동작이 발생할 수 있습니다.
강제 보류 중인 I/O 요청을 사용하는 이유는 무엇인가요?
드라이버 스택의 상위 수준 드라이버는 IoCallDriver 를 호출하여 IRP를 드라이버 스택의 하위 수준 드라이버로 전달합니다. 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 이상 버전의 Windows에서만 지원됩니다.
명령줄에서
보류 중인 I/O 요청 강제를 활성화하려면 플래그 값 0x210 사용하거나 플래그 값에 0x210 추가합니다. 이 값은 I/O 확인(0x10) 및 보류 중인 I/O 요청 강제 적용(0x200)을 활성화합니다.
예:
verifier /flags 0x210 /driver MyDriver.sys
옵션은 다음 부팅 후 활성화됩니다.
보류 중인 I/O 요청 강제(검증 도구 /플래그 0x200)만 활성화하려는 경우 드라이버 검증 도구는 0x200(강제 보류 중인 I/O 요청) 및 I/O 확인을 모두 자동으로 사용하도록 설정합니다.
명령에 /volatile 매개 변수를 추가하여 컴퓨터를 다시 부팅하지 않고 보류 중인 I/O 요청 강제 활성화 및 비활성화할 수도 있습니다. 예:
verifier /volatile /flags 0x210 /adddriver MyDriver.sys
이 설정은 즉시 유효하지만 컴퓨터를 종료하거나 다시 부팅하면 손실됩니다. 자세한 내용은 Volatile 설정 사용을 참조하세요.
드라이버 검증 도구 관리자 사용
- 드라이버 검증 도구 관리자를 시작합니다. 명령 프롬프트 창에 검증 도구 를 입력합니다.
- 사용자 지정 설정 만들기(코드 개발자용)를 선택하고 다음을 클릭합니다.
- 전체 목록에서 개별 설정 선택을 선택합니다.
- 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 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.sys pci에 STATUS_PENDING 반환했습니다 . PciCallDownIrpStack. 이 호출로 인해 충돌이 발생한 경우 드라이버 소유자는 pci에 대한 소스 코드를 검토해야 합니다 . PciCallDownIrpStack 을 수정하여 STATUS_PENDING 올바르게 처리합니다.