INVALID_MDL_RANGE

Hi,
I am trying to port a 32 bit filter driver to 64 bit environment. The code works perfectly in 32 bit environment. Basically, the filter driver intercepts the IO’s on the block device it is associated with and does prefetch of the IO by prepend/appending MDL’s to the passed in MDL and linking them using PDML *Next field. This logic worked fine for 32 bit OS.

For 64 bit OS, i hit invlaid_mdl_range bugcheck while trying to do filesystem IO.
Lower driver is trying to create a partial MDL. But it gives an address range and size which is beyond the source mdl. Hence the bug check.

Need to know if there is any limitation with 64 bit windows driver environment. Want to know how to fix this.

Crash analysis below.

WINDBG Analysis

INVALID_MDL_RANGE (12e)
A driver has called the IoBuildPartialMdl() function and passed it an MDL
to map part of a source MDL, but the virtual address range specified is
outside the range in the source MDL. This is a driver bug. The source
and target MDLs, as well as the address range length to be mapped are the
arguments to the IoBuildPartialMdl() function, i.e.;
IoBuildPartialMdl(
IN PMDL SourceMdl,
IN OUT PMDL TargetMdl,
IN PVOID VirtualAddress,
IN ULONG Length
)
Arguments:
Arg1: fffffa8007a061b0 <-------- First MDL in the MDL chain. This is of 4096 bytes size.
Arg2: fffffa8007930440
Arg3: fffffa8007596000 <-------- Base VA from which the lower driver trying to create
partial MDL. Address is 256 LBA’s beyond the source MDL
which is wrong. Leading to bugcheck.

Arg4: 0000000000004000 <----- Size is 32 LBA’s. But the actual size of the MDL itself is 8
LBA’s only.

FAULTING_MODULE: fffff8000165c000 nt

DEBUG_FLR_IMAGE_TIMESTAMP: 4a5bc11e

DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

BUGCHECK_STR: 0x12E

CURRENT_IRQL: 0

LAST_CONTROL_TRANSFER: from fffff800017231d6 to fffff800016cdf00

STACK_TEXT:
fffff880050cb448 fffff800017231d6 : 000000000000012e fffffa8007a061b0 fffffa8007930440 fffffa8007596000 : nt!KeBugCheckEx
fffff880050cb450 fffff8800191850f : 0000000000000000 0000000000000000 fffffa8006aec8f0 0000000000030000 : nt!wcsncat_s+0x49ee
fffff880050cb490 fffff88001918695 : fffffa800796e530 fffffa80069b1060 0000000000020000 0000000100000000 : CLASSPNP+0x150f
fffff880050cb530 fffff880047d09ed : fffffa8007ac8c60 fffffa8007ac8c60 fffffa8007ac8ee0 0000000000001001 : CLASSPNP+0x1695
fffff880050cb580 fffff880047d60fe : fffffa8007768dd0 fffffa8007edb008 fffffa8007f0a000 fffff880047d4dbb : mrfilter!MRFilterDispatchIO+0x38d [c:\zcache\winclient\mrfilter.c @ 1153]
fffff880050cb610 fffff880047d4909 : fffffa8007768dd0 fffffa8007f0a000 0000000000000002 0000000000000111 : mrfilter!fcm_handle_disk_read+0x15e [c:\zcache\winclient\fcm.c @ 2130]
fffff880050cb660 fffff880047d32ee : fffffa8007768dd0 fffff880050cb750 fffff880047dc4e0 0000000000000272 : mrfilter!fcm_handle_cache_read+0x559 [c:\zcache\winclient\fcm.c @ 1376]
fffff880050cb720 fffff880047d34ce : fffffa8007768dd0 fffff800017864bc fffffa8007edb008 0000000002000000 : mrfilter!fcm_schedule_io_req2+0xce [c:\zcache\winclient\fcm.c @ 652]
fffff880050cb780 fffff880047d011b : fffffa8007768dd0 000000000000029e 0000000000000100 0000000000000098 : mrfilter!fcm_schedule_io_req+0x5e [c:\zcache\winclient\fcm.c @ 737]
fffff880050cb7d0 fffff880010540af : fffffa800794a550 fffffa8007ac8c60 fffffa80079dadd0 0000007fffffffff : mrfilter!MRFilterReadWrite+0x7eb [c:\zcache\winclient\mrfilter.c @ 885]
fffff880050cb870 fffff8800106912c : fffffa8007a52a70 fffffa8007ac8c60 fffffa8006e84950 0000000001fe18c0 : partmgr+0x10af
fffff880050cb8a0 fffff8800189341f : fffffa8007ac8c60 fffffa8007ac8c60 fffffa8007ada360 fffffa80079dadd0 : volmgr+0x112c
fffff880050cb8e0 fffff8000193a028 : fffffa8007ac8f70 00001f800100e9a8 0000000000000000 0000000002002000 : volsnap+0x141f
fffff880050cb910 fffff80001938cfd : 0000000000000000 fffffa80079dadd0 fffffa8007ac8c60 0000000000000000 : nt!IoBuildSynchronousFsdRequest+0x168
fffff880050cb950 fffff880012ae6af : fffffa8006e84950 0000000000000001 fffffa8007ac8c60 fffffa8006e84950 : nt!PsRevertToSelf+0x6b5
fffff880050cb9b0 fffff800019e1929 : 0000000000000000 fffffa80079dadd0 0000000000000001 fffffa8007ac8c60 : fltmgr+0x16af
fffff880050cba10 fffff800019e9143 : fffffa80079dadd0 fffffa80079dad01 fffffa80079dadd0 0000000000000002 : nt!IoRemoveShareAccess+0x169
fffff880050cba80 fffff800016cd153 : 0000000000000801 0000000000000000 0000000000000000 0000000000000000 : nt!NtReadFile+0x633
fffff880050cbb70 000000007751ff1a : 0000000000000000 0000000000000000 0000000000000000 0000000000000000 : nt!KeSynchronizeExecution+0x3a43
000000000190ca08 0000000000000000 : 0000000000000000 0000000000000000 0000000000000000 0000000000000000 : 0x7751ff1a

STACK_COMMAND: kb

FOLLOWUP_IP:
CLASSPNP+150f
fffff880`0191850f 4c8b5e20 mov r11,qword ptr [rsi+20h]

SYMBOL_STACK_INDEX: 2

SYMBOL_NAME: CLASSPNP+150f

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: CLASSPNP

IMAGE_NAME: CLASSPNP.SYS

BUCKET_ID: WRONG_SYMBOLS

Followup: MachineOwner

User Debug Prints

MRFilterReadWrite : FFFFFA8007768DD0
MRFilterReadWrite : Read IO 1

----- IO size 256 lbas. Start Lba 152, User mdl FFFFFA8007AC6520, READ IO ------

CMDNO:670 MRFilterReadWrite : FCM… size 256 lba 152 mdl FFFFFA8007AC6520 IOtype 3

----- Prepend three 4K buffers and append one 4K buffer to the passed in MDL using
PMDL Next; field --------------

CMDNO:670 MRFilterPrependMdl : Buf FFFFFA800768E000 len 4096 Offset 0 freq FFFFFA8007768DD0 bufOff FFFFFA800768E000
CMDNO:670 MRFilterPrependMdl : len 135168 byteoffset 73728

CMDNO:670 MRFilterPrependMdl : Buf FFFFFA8007725000 len 4096 Offset 0 freq FFFFFA8007768DD0 bufOff FFFFFA8007725000
CMDNO:670 MRFilterPrependMdl : len 139264 byteoffset 69632

CMDNO:670 MRFilterPrependMdl : Buf FFFFFA8007576000 len 4096 Offset 0 freq FFFFFA8007768DD0 bufOff FFFFFA8007576000
CMDNO:670 MRFilterPrependMdl : len 143360 byteoffset 65536

CMDNO:670 MRFilterAppendMdl : Buf FFFFFA800772A000 len 4096 Offset 0 freq FFFFFA8007768DD0 bufOff FFFFFA800772A000
CMDNO:670 MRFilterAppendMdl : len 147456

------------- IO SIZE in bytes 147456. Start LBA in bytes is 65536 ----------

READ 147456 65536

--------- MDL address, Base Virtual Address and ByteCount of MDL’s are all correct.
This is printed just before doing IoCallDriver to send the io to lower driver ----

MDL FFFFFA8007A061B0 BaseVa FFFFFA8007576000 Cnt 4096
MDL FFFFFA80074BF5D0 BaseVa FFFFFA8007725000 Cnt 4096
MDL FFFFFA80075CD110 BaseVa FFFFFA800768E000 Cnt 4096
MDL FFFFFA8007AC6520 BaseVa 0000000001FE18C0 Cnt 131072 <— original MDL.
MDL FFFFFA8007A4C1B0 BaseVa FFFFFA800772A000 Cnt 4096

Before I start, I’ll note that your symbols are incorrect. Try:

.symfix c:\websymbols
.reload

Before running !analyze -v.

Basically, the filter driver intercepts the IO’s on the block device it is
associated with and does prefetch of the IO by >prepend/appending MDL’s to
the passed in MDL and linking them using PDML *Next field.

As far as I know, the storage branch has never been documented to support
chained MDLs. So, I’d consider yourself lucky if it’s ever actually worked
for you (or unlucky, as the case may be).

As to why the system crashed, here are are the base address and length from
the crash:

Arg3: fffffa8007596000
Arg4: 0000000000004000

And here’s the MDL chain that you’re sending:

MDL FFFFFA8007A061B0 BaseVa FFFFFA8007576000 Cnt 4096
MDL FFFFFA80074BF5D0 BaseVa FFFFFA8007725000 Cnt 4096
MDL FFFFFA80075CD110 BaseVa FFFFFA800768E000 Cnt 4096
MDL FFFFFA8007AC6520 BaseVa 0000000001FE18C0 Cnt 131072 <— original MDL.
MDL FFFFFA8007A4C1B0 BaseVa FFFFFA800772A000 Cnt 4096

Busting out the trusty calculator, that chain adds up to a total transfer of
0x24000 bytes. Your crash indicates that the class driver is trying to build
an MDL of 0x4000 bytes, so it would appear that the storage adapter has a
max transfer size of 0x20000 bytes and we’re on stage two of the transfer.

We’ve successfully staged the first portion of the transfer, but now we’re
building an MDL to describe the second stage of the transfer. The way the
class driver does this is by building a partial MDL for the remainder of the
transfer. Basically something like:

IoBuildPartialMdl(OriginalMdl, PartialMdl, DataBuffer+transferredSoFar,
lengthRemaining);

Because the data buffer pointer comes out of the first MDL, you have
FFFFFA8007576000+0x20000 passed as the data buffer and 0x4000 passed as the
remaining length. IoBuildPartialMdl doesn’t evaluate the MDL chain when
calculating the length of the MDL supplied, it instead simply grabs the byte
count out of the MDL. Because the byte count is 0x1000 here and the
calculated offset into the MDL for the transfer is 0x20000, the system
crashes.

Note that the first stage of the transfer was processed without crashing
because the class driver doesn’t build a partial MDL for the first stage, it
just uses the MDL directly. You can confirm this yourself by reading the
source, which is available in the WDK.

Without further reading of the class driver, I’d say that this confirms the
theory that it doesn’t support MDL chains. If that’s the case your design is
flawed and not going to work in Windows (32bit or 64bit).

-scott


Scott Noone
Consulting Associate and Chief System Problem Analyst
OSR Open Systems Resources, Inc.
http://www.osronline.com

Hi Scott,

Thanks for your valuable reply. Now I understood the crash.

I have one more question.
This test was run on 64-bit enterprise edition.
I did the same test on 64-bit standard edition. There it doesn’t crash.

Is it becoz Class driver knows about MDL chain?.
Or the IO range detected by the class driver is beyond 256 LBA’s. So it doesn’t split the IO. Hence no issues?.

Thanks.

Storage stack doesn’t support chained MDLs. Too bad for you.

It probably just means that the request isn’t being broken up across
multiple transfers. You can install your own version of classpnp.sys built
from source and step through to verify, but in the end chained MDLs just
don’t work here.

-scott


Scott Noone
Consulting Associate and Chief System Problem Analyst
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…

Hi Scott,

Thanks for your valuable reply. Now I understood the crash.

I have one more question.
This test was run on 64-bit enterprise edition.
I did the same test on 64-bit standard edition. There it doesn’t crash.

Is it becoz Class driver knows about MDL chain?.
Or the IO range detected by the class driver is beyond 256 LBA’s. So it
doesn’t split the IO. Hence no issues?.

Thanks.