다음을 통해 공유


IRP_MN_QUERY_STOP_DEVICE 요청 처리(Windows 2000 이상)

IRP_MN_QUERY_STOP_DEVICE 요청은 먼저 디바이스 스택의 상위 드라이버에 의해 처리된 다음 각 하위 드라이버에 의해 처리됩니다. 드라이버는 DispatchPnP 루틴에서 중지 IRP를 처리합니다.

IRP_MN_QUERY_STOP_DEVICE 대한 응답으로 드라이버는 다음을 수행해야 합니다.

  1. 디바이스를 중지할 수 있는지 여부와 해당 하드웨어 리소스가 부정적인 영향을 주지 않고 해제되었는지 확인합니다.

    다음 중 하나라도 true인 경우 드라이버는 쿼리 중지 IRP에 실패해야 합니다.

    • 드라이버에 디바이스가 페이징, 최대 절전 모드 또는 크래시 덤프 파일의 경로에 있음을 (IRP_MN_DEVICE_USAGE_NOTIFICATION 통해) 알림을 받았습니다.

    • 디바이스의 하드웨어 리소스를 해제할 수 없습니다.

    다음이 true인 경우 드라이버가 쿼리 중지 IRP에 실패할 수 있습니다.

    • 드라이버는 I/O 요청을 삭제해서는 안 되며 IRP를 큐에 대기시키는 메커니즘이 없습니다.

      디바이스가 중지된 상태인 동안 드라이버는 디바이스에 액세스해야 하는 IRP를 보유해야 합니다. 드라이버가 IRP를 큐에 대기하지 않는 경우 디바이스를 중지하도록 허용하면 안 되므로 쿼리 중지 IRP에 실패해야 합니다.

      이 규칙의 예외는 I/O를 삭제할 수 있는 디바이스입니다. 이러한 디바이스에 대한 드라이버는 IRP를 큐에 대기하지 않고 쿼리 중지 및 중지 요청에 성공할 수 있습니다.

  2. 디바이스를 중지할 수 없는 경우 쿼리 중지 IRP에 실패합니다.

    Irp-IoStatus.Status>를 적절한 오류 상태 설정하고, IO_NO_INCREMENT 사용하여 IoCompleteRequest를 호출하고, 드라이버의 DispatchPnP 루틴에서 반환합니다. IRP를 다음 하위 드라이버에 전달하지 마세요.

  3. 디바이스를 중지할 수 있고 드라이버가 IRP를 큐에 대기하는 경우 후속 IRP가 큐에 대기되도록 디바이스 확장에서 HOLD_NEW_REQUESTS 플래그를 설정합니다( 디바이스가 일시 중지될 때 들어오는 IRP 유지 참조).

    또는 디바이스용 드라이버는 드라이버가 후속 IRP_MN_STOP_DEVICE 요청을 받을 때까지 디바이스 일시 중지를 완전히 연기할 수 있습니다. 그러나 이러한 드라이버는 도착 시 중지 IRP를 즉시 성공하지 못하게 하는 모든 요청을 큐에 대기해야 합니다. 디바이스가 다시 시작될 때까지 이러한 드라이버는 다음과 같은 요청을 큐에 대기해야 합니다.

    • IRP_MN_DEVICE_USAGE_NOTIFICATION 요청(예: 디바이스에 페이징 파일 배치).

    • 등시 전송에 대한 요청입니다.

    • 드라이버가 중지 IRP에 성공하지 못하도록 하는 요청을 만듭니다.

  4. 디바이스에 진행 중인 IRP가 실패할 수 없는 경우 다른 드라이버 루틴 및 낮은 드라이버에 전달된 미해결 요청이 완료되었는지 확인합니다.

    드라이버에서 이 작업을 수행할 수 있는 한 가지 방법은 참조 수와 이벤트를 사용하여 모든 요청이 완료되었는지 확인하는 것입니다.

    • AddDevice 루틴에서 드라이버는 디바이스 확장에서 I/O 참조 수를 정의하고 개수를 1로 초기화합니다.

    • 또한 AddDevice 루틴에서 드라이버는 KeInitializeEvent 를 사용하여 이벤트를 만들고 KeClearEvent를 사용하여 이벤트를 Not-Signaled 상태로 초기화합니다.

    • IRP를 처리할 때마다 드라이버는 InterlockedIncrement를 사용하여 참조 수를 증분합니다.

    • 요청을 완료할 때마다 드라이버는 InterlockedDecrement를 사용하여 참조 수를 감소합니다.

      드라이버가 요청에 IoCompletion 루틴을 사용하지 않는 경우 IoCallDriver 호출 직후 또는 요청이 있는 경우 IoCompletion 루틴의 참조 수를 감소합니다.

    • 드라이버가 IRP_MN_QUERY_STOP_DEVICE 받으면 InterlockedDecrement를 사용하여 참조 수가 감소합니다. 미해결 요청이 없으면 참조 수가 0으로 줄어듭니다.

    • 참조 수가 0에 도달하면 드라이버는 쿼리 중지 코드를 계속할 수 있음을 알리는 KeSetEvent 를 사용하여 이벤트를 설정합니다.

    위의 프로시저 대신 드라이버는 진행 중인 모든 IRP 뒤에 IRP_MN_QUERY_STOP_DEVICE IRP를 직렬화할 수 있습니다.

  5. 디바이스를 중지 보류 상태로 두는 데 필요한 다른 단계를 수행합니다.

    드라이버가 쿼리 중지 IRP에 성공하면 IRP_MN_STOP_DEVICE 성공할 준비가 되어 있어야 합니다.

  6. IRP를 완료합니다.

    함수 또는 필터 드라이버에서:

    • Irp-IoStatus.Status>를 STATUS_SUCCESS 설정합니다.

    • IoSkipCurrentIrpStackLocation을 사용하여 다음 스택 위치를 설정하고 IRP를 IoCallDriver를 사용하여 다음 하위 드라이버에 전달합니다.

    • IoCallDriver에서 상태 DispatchPnP 루틴에서 반환 상태 전파합니다.

    • IRP를 완료하지 마세요.

    버스 드라이버에서:

    • Irp-IoStatus.Status>를 STATUS_SUCCESS 설정합니다.

      그러나 버스의 디바이스가 하드웨어 리소스를 사용하는 경우 버스 및 자식 디바이스의 리소스 요구 사항을 다시 평가합니다. 요구 사항이 변경된 경우 STATUS_SUCCESS 대신 STATUS_RESOURCE_REQUIREMENTS_CHANGED 반환합니다. 이 상태 성공을 나타내지만 PnP 관리자가 중지 IRP를 보내기 전에 리소스를 다시 쿼리할 것을 요청합니다.

    • IO_NO_INCREMENT 사용하여 IRP(IoCompleteRequest)를 완료합니다.

    • DispatchPnP 루틴에서 반환합니다.

디바이스 스택의 드라이버가 IRP_MN_QUERY_STOP_DEVICE 실패하면 PnP 관리자는 디바이스 스택에 IRP_MN_CANCEL_STOP_DEVICE 보냅니다. 이렇게 하면 드라이버가 쿼리 중지 IRP에 대한 IoCompletion 루틴을 요구하여 하위 드라이버가 IRP에 실패했는지 여부를 감지할 수 없습니다.