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:

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

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

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

  1. Call IoAllocateMdl to allocate an MDL describing a portion of the user buffer.

  2. Call MmProbeAndLockPages to lock down that portion of the user buffer.

  3. Transfer the data for that portion of the buffer.

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

  5. Call MmUnlockPages and IoFreeMdl when all the data has been transferred.