16.4.1.2 Setting up MDLs for Partial Transfer Requests
If a transfer request is too large for the underlying device driver to handle,
a higher-level driver can call IoBuildPartialMdl and set up a sequence
of partial-transfer IRPs for the underlying device driver(s).
If a highest-level driver cannot lock down the entire user buffer with MmProbeAndLockPages
in a machine with limited memory, the original request also must be split into
partial transfers. For such a large transfer request, a highest-level driver
can do the following:
-
Call IoBuildSynchronousFsdRequest to allocate a partial-transfer IRP
and lock down a portion, which is usually a multiple of PAGE_SIZE or sized to
suit the underlying device’s transfer capacity, of the user buffer.
-
Call IoCallDriver with the partial-transfer IRP and KeWaitForSingleObject
to wait on the event object that the driver set up to be associated with its
partial-transfer IRP if lower driver(s) return STATUS_PENDING.
-
When it regains control, repeat Steps 1 and 2 until all the data has been
transferred, and, then, complete the original IRP.
A highest-level device driver that must handle very large transfer requests
can use the preceding technique and simply call itself with the
partial-transfer IRPs it allocates. As an alternative, such a highest-level
device driver can do the following:
-
Call IoAllocateMdl to allocate an MDL describing a portion of the user
buffer.
-
Call MmProbeAndLockPages to lock down that portion of the user buffer.
-
Transfer the data for that portion of the buffer.
-
Call MmUnlockPages and do either of the following:
-
If the MDL that the driver allocated in Step 1 is large enough for the next
piece of the transfer, call MmPrepareMdlForReuse and, then, repeat
Steps 2 through 4.
-
Otherwise, call IoFreeMdl and repeat Steps 1 through 4.
-
Call MmUnlockPages and IoFreeMdl when all the data has been
transferred.