버퍼링된 I/O 사용

대화형 또는 느린 디바이스를 서비스하는 드라이버 또는 일반적으로 한 번에 비교적 적은 양의 데이터를 전송하는 드라이버는 버퍼링된 I/O 전송 방법을 사용해야 합니다. 작은 대화형 전송에 버퍼링된 I/O를 사용하면 메모리 관리자가 직접 I/O를 요청하는 드라이버와 마찬가지로 각 전송에 대한 전체 물리적 페이지를 잠글 필요가 없으므로 전반적인 실제 메모리 사용량이 향상됩니다. 일반적으로 비디오, 키보드, 마우스, 직렬 및 병렬 드라이버는 버퍼링된 I/O를 요청합니다.

I/O 관리자는 다음과 같이 I/O 작업이 버퍼링된 I/O를 사용하고 있음을 확인합니다.

다음 그림에서는 I/O 관리자가 버퍼링된 I/O를 사용하는 전송 작업에 대한 IRP_MJ_READ 요청을 설정하는 방법을 보여 줍니다.

사용자 버퍼에 대한 버퍼링된 i/o를 보여 주는 다이어그램

이 그림은 드라이버가 디바이스 개체의 Flags를 DO_BUFFERED_IO 사용하여 ORed한 경우 드라이버가 IRP의 SystemBuffer 포인터를 사용하여 읽기 요청에 대한 데이터를 전송하는 방법에 대한 개요를 보여 줍니다.

  1. 일부 사용자 공간 가상 주소 범위는 현재 스레드의 버퍼를 나타내며, 해당 버퍼의 콘텐츠는 페이지 기반 실제 주소 범위(이전 그림의 어두운 음영) 내에 어딘가에 저장될 수 있습니다.

  2. I/O 관리자는 스레드가 버퍼를 나타내는 다양한 사용자 공간 가상 주소를 전달하는 현재 스레드의 읽기 요청을 처리합니다.

  3. I/O 관리자는 사용자가 제공한 버퍼의 접근성을 확인하고 ExAllocatePoolWithTag 를 호출하여 사용자가 제공한 버퍼의 크기인 비페이지 시스템 공간 버퍼(SystemBuffer)를 만듭니다.

  4. I/O 관리자는 드라이버에 보내는 IRP에서 새로 할당된 SystemBuffer 에 대한 액세스를 제공합니다.

    그림에 쓰기 요청이 표시된 경우 I/O 관리자는 IRP를 드라이버로 보내기 전에 사용자 버퍼에서 시스템 버퍼로 데이터를 복사합니다.

  5. 이전 그림에 표시된 읽기 요청의 경우 드라이버는 디바이스에서 시스템 공간 버퍼로 데이터를 읽습니다. 이 버퍼의 메모리는 페이징되지 않으며 드라이버는 버퍼를 먼저 잠그지 않고도 안전하게 액세스할 수 있습니다. 읽기 요청이 충족되면 드라이버는 IRP를 사용하여 IoCompleteRequest 를 호출합니다.

  6. 원래 스레드가 다시 활성화되면 I/O 관리자는 시스템 버퍼의 읽기-인 데이터를 사용자 버퍼에 복사합니다. 또한 ExFreePool 을 호출하여 시스템 버퍼를 해제합니다.

I/O 관리자가 드라이버에 대한 시스템 공간 버퍼를 만든 후 요청된 사용자 모드 스레드를 교환할 수 있으며 다른 프로세스에 속한 스레드에서 실제 메모리를 다시 사용할 수 있습니다. 그러나 드라이버가 IRP를 사용하여 IoCompleteRequest 를 호출할 때까지 IRP에 제공된 시스템 공간 가상 주소 범위는 유효한 상태로 유지됩니다.

많은 양의 데이터를 한 번에 전송하는 드라이버, 특히 다중 페이지 전송을 수행하는 드라이버는 버퍼링된 I/O를 사용하려고 시도해서는 안 됩니다. 시스템이 실행되면 I/O 관리자가 이러한 드라이버에 대해 IRP로 보낼 큰 연속 시스템 공간 버퍼를 할당할 수 없도록 페이지가 없는 풀이 조각화될 수 있습니다.

일반적으로 드라이버는 직접 I/O를 사용하는 경우에도 IRP_MJ_DEVICE_CONTROL 요청과 같은 일부 유형의 IRP에 버퍼링 된 I/O를 사용합니다. 일반적으로 직접 I/O를 사용하는 드라이버는 IRP_MJ_READIRP_MJ_WRITE 요청과 대용량 데이터 전송이 필요한 드라이버 정의 IRP_MJ_INTERNAL_DEVICE_CONTROL 요청에 대해서만 이 작업을 수행합니다.

모든 IRP_MJ_DEVICE_CONTROLIRP_MJ_INTERNAL_DEVICE_CONTROL 요청에는 I/O 제어 코드가 포함됩니다. I/O 컨트롤 코드가 버퍼링된 I/O를 사용하여 IRP를 지원해야 한다고 나타내는 경우 I/O 관리자는 단일 시스템 버퍼를 사용하여 사용자 애플리케이션의 입력 및 출력 버퍼를 나타냅니다. 이러한 I/O 제어 코드를 지원하는 드라이버는 버퍼에서 입력 데이터(있는 경우)를 읽은 다음 입력 데이터를 덮어써 출력 데이터(있는 경우)를 제공해야 합니다. 자세한 내용은 I/O 제어 코드 정의를 참조하세요.