Can I use MmGetMdlPfnArray API to merge buffers in the filter driver ??

Can I use MmGetMdlPfnArray API to merge data buffer pointed by MDL in the filter driver which sits below Disk Class? Is it ok to use this API to get PFN array and read and modify the contents of it ?

Suppose I need to merge two buffers pointed by irp1->MdlAddr and irp2->MdlAddr. I will be doing the following

  1. Get PFN array of irp1->MdlAddr and irp2->MdlAddr, read the contents of it
  2. Allocate a new MDL with size of MDL1+MDL2
  3. Get the PFN array of newly allocated MDL and copy the contents of PFN array of MDL1 and MDL2 to newly allocated MDL.

Please let me know if MmGetMdlPfnArray can be used to perform the operation mentioned below.

Sample snippet to copy the source mdl “srcmdl” to newly allocated MDL “destmdl” (this is not for merging). This is just to copy the contents of srcmdl pointed by irp to newly allocated mdl.

PMDL srcmdl,destmdl;
PPFN_NUMBER mdlAddrArray, mdlDestAddrArray;
u32 mdlAddrArrayIndex, mdlDestAddrArrayIndex, page_offset, srcbytes ;
u32 noofentries=0;
PVOID srcVirtualAddress = NULL;
PIRP irp = NULL;

irp = WdfRequestWdmGetIrp(Request);
srcmdl = irp->MdlAddress;

/* Get PFN array of src mdl */
mdlAddrArray = MmGetMdlPfnArray(srcmdl);
page_offset = MmGetMdlByteOffset(srcmdl);
mdlAddrArrayIndex = 0;

/* Bytes described by MDL*/
srcbytes = MmGetMdlByteCount(srcmdl);

/* Calculate no of PFN entries */
noofentries = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(srcmdl), MmGetMdlByteCount(srcmdl));

/* Get the base virtual address described by MDL */
srcVirtualAddress = MmGetMdlVirtualAddress(srcmdl);

/* Allocate Target MDL */
destmdl = IoAllocateMdl(srcVirtualAddress, srcbytes, FALSE, FALSE, irp);

/* Get PFN array of dest mdl */
mdlDestAddrArray = MmGetMdlPfnArray(destmdl);
mdlDestAddrArrayIndex = 0;
while(noofentries)
{
mdlDestAddrArray[mdlDestAddrArrayIndex++] = (mdlAddrArray[mdlAddrArrayIndex++]) + page_offset;
page_offset = 0;
noofentries–;
}

DK

I think this is why this API is documented (not for DMA purposes for sure!).

There was once an AGP440 driver sample in the WDK, it contained this code IIRC.

Also note: Windows disk stack does not support chained MDLs or scattered IO, this is not “struct bio” in Linux.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntdev…
> Can I use MmGetMdlPfnArray API to merge data buffer pointed by MDL in the filter driver which sits below Disk Class? Is it ok to use this API to get PFN array and read and modify the contents of it ?
>
> Suppose I need to merge two buffers pointed by irp1->MdlAddr and irp2->MdlAddr. I will be doing the following
> 1) Get PFN array of irp1->MdlAddr and irp2->MdlAddr, read the contents of it
> 2) Allocate a new MDL with size of MDL1+MDL2
> 3) Get the PFN array of newly allocated MDL and copy the contents of PFN array of MDL1 and MDL2 to newly allocated MDL.
>
> Please let me know if MmGetMdlPfnArray can be used to perform the operation mentioned below.
>
> Sample snippet to copy the source mdl “srcmdl” to newly allocated MDL “destmdl” (this is not for merging). This is just to copy the contents of srcmdl pointed by irp to newly allocated mdl.
>
>
> PMDL srcmdl,destmdl;
> PPFN_NUMBER mdlAddrArray, mdlDestAddrArray;
> u32 mdlAddrArrayIndex, mdlDestAddrArrayIndex, page_offset, srcbytes ;
> u32 noofentries=0;
> PVOID srcVirtualAddress = NULL;
> PIRP irp = NULL;
>
> irp = WdfRequestWdmGetIrp(Request);
> srcmdl = irp->MdlAddress;
>
> /* Get PFN array of src mdl /
> mdlAddrArray = MmGetMdlPfnArray(srcmdl);
> page_offset = MmGetMdlByteOffset(srcmdl);
> mdlAddrArrayIndex = 0;
>
> /
Bytes described by MDL*/
> srcbytes = MmGetMdlByteCount(srcmdl);
>
> /* Calculate no of PFN entries /
> noofentries = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(srcmdl), MmGetMdlByteCount(srcmdl));
>
> /
Get the base virtual address described by MDL /
> srcVirtualAddress = MmGetMdlVirtualAddress(srcmdl);
>
>
> /
Allocate Target MDL /
> destmdl = IoAllocateMdl(srcVirtualAddress, srcbytes, FALSE, FALSE, irp);
>
> /
Get PFN array of dest mdl */
> mdlDestAddrArray = MmGetMdlPfnArray(destmdl);
> mdlDestAddrArrayIndex = 0;
> while(noofentries)
> {
> mdlDestAddrArray[mdlDestAddrArrayIndex++] = (mdlAddrArray[mdlAddrArrayIndex++]) + page_offset;
> page_offset = 0;
> noofentries–;
> }
>
> DK
>