3.2.4.1 Using Buffered I/O

Figure 3.3 illustrates how the I/O Manager sets up an IRP requesting a transfer operation for drivers that OR their device object(s)’ Flags with DO_BUFFERED_IO.

Figure 3.3 Buffered I/O for User Buffers

As Figure 3.3 shows, some range of user-space virtual addresses represents the current thread’s buffer, and that buffer’s contents might be stored somewhere within a range of page-based physical addresses.

Figure 3.3 also shows an overview of how drivers can use the SystemBuffer pointer in the IRP to transfer data for a read request, when a driver has ORed the device object’s Flags with DO_BUFFERED_IO:

  1. The I/O Manager services the current thread’s read request, for which the thread passes a range of user-space virtual addresses representing a buffer.

  2. The I/O Manager checks the user-supplied buffer for accessibility and calls ExAllocatePool to create a resident system-space buffer the size of the user-supplied buffer. It provides access to the newly allocated SystemBuffer in the IRP it sends to the driver.

    If Figure 3.3 showed a write request, the I/O Manager would copy data from the user buffer into the system buffer before it sent the IRP to the driver.

  3. For the read request shown in Figure 3.3, the driver reads data from the device into the system-space buffer.

  4. When the driver has called IoCompleteRequest with the IRP and the original thread is again current, the I/O Manager copies the read-in data from the system buffer into the user buffer. It also calls ExFreePool to release the system buffer and disposes of the IRP.

After the I/O Manager has created a system-space buffer for the driver, the requesting user-mode thread can be swapped out and its physical memory can be reused by another thread, possibly by a thread belonging to another process. However, the system-space virtual address range supplied in the IRP remains valid until the driver calls IoCompleteRequest with the IRP.

NT drivers for devices that do not transfer large amounts of data at a time, such as interactive devices, can use buffered I/O.

NT drivers that transfer large amounts of data at a time, in particular, drivers that do multipage transfers, should not attempt to use buffered I/O. As the system runs, nonpaged pool can become fragmented so that the I/O Manager cannot allocate large, contiguous system-space buffers to send in IRPs for such a driver.

Note that all NT drivers use buffered I/O for certain IRP_MJ_XXX. Even NT drivers that set up their device objects for direct I/O use buffered I/O for most requests except IRP_MJ_READ, IRP_MJ_WRITE, and, possibly, driver-defined IRP_MJ_INTERNAL_DEVICE_CONTROL requests that require large data transfers.