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:
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.
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.