sending a cloned IRP down the filter chain

I am trying to write a minifilter that does the following:

  1. Intercept DirectoryControl/NotifyDirectory IRPs
  2. Clones the IRP
  3. Sends the cloned IRP down the filter chain
  4. Pends the original IRP

Then,

  1. After the cloned IRP completes, copies the result (and buffer) back to
    the original IRP
  2. Discards the cloned IRP
  3. Completes the original IRP

I’m running into a problem when I allocate a buffer for the clone IRP. If I
allocate NonPagedPool (as all of the minifilter examples do), everything
works perfectly. However, if I try to allocate PagedPool, I get a bugcheck
when I try to lock those pages in my AsynchronousIo callback. Here is my
current order of operations:

In PreOpCallback:

  1. Create a clone IRP and copy the Iopb block from the original.
  2. Call newBuffer = ExAllocatePoolWithTag(PagedPool, … )
  3. Call newMdl = IoAllocateMdl(newBuffer, length, FALSE, FALSE, NULL)
  4. Do NOT call MmBuildMdlForNonPagedPool.
  5. Send the cloned IRP down using FltPerformAsynchronousIo

Then, in the asynchronous Io callback I try to access the buffer as follows:

try
{

  1. MmProbeAndLockPages ( … ) <– ** bugcheck occurs here **
  2. MmGetSystemAddressForMdlSafe( … )
  3. Copy the buffer
  4. MmUnlockPages( … )
    }
    except { … }

I’m receiving a bugcheck on MmProbeAndLockPages. Is there something I’m
forgetting to do? In the documentation for swapping buffers, it says “…the
buffer can be allocated from either paged or nonpaged pool, and the
minifilter driver must always create and set an MDL.” Is it enough just to
allocate the MDL, or is there something else I need to do with it before I
send it down the filter chain? Is there something I’m forgetting to do
between allocating the memory on the way down and locking the pages on the
way up?

My motivation for using paged memory is because NotifyDirectory IRPs can
potentially live in the bowels of the filesystem for long periods of time
waiting for something to happen, at which point they are sent back up the
filter chain. I don’t want to use NonPagedPool and lock pages while my IRP
is sitting idle.

> Is there something I’m forgetting to do?

Yes, you forget to ponder your design. What happens if the following code is
executed at DISPATCH_LEVEL?

  1. MmProbeAndLockPages ( … ) <– ** bugcheck occurs here **
  2. MmGetSystemAddressForMdlSafe( … )
  3. Copy the buffer
  4. MmUnlockPages( … )

Put the following piece of code before calling MmProbeAndLockPages -

if( KeGetCurrentIrql() == DISPATCH_LEVEL ){
KeBugCheck( 0xAAAAAAA, 0x0, 0x0, 0x0, 0x0 );
}
MmProbeAndLockPages …

Actually, your code with MmProbeAndLockPages at the completion callback(
i.e. the way up ) looks useless and wrong - why you need to block a buffer
in the place where it has had to be blocked?
MDL is used to provide access at high IRQLs to data which might be paged
out, and this data must have been blocked before IRQL rises.
If you still want to use this design - then defer completion until it is
safe by using FltDoCompletionProcessingWhenSafe.


Slava Imameyev, xxxxx@hotmail.com

“Michael Carr” wrote in message news:xxxxx@ntfsd…
>I am trying to write a minifilter that does the following:
>
> 1. Intercept DirectoryControl/NotifyDirectory IRPs
> 2. Clones the IRP
> 3. Sends the cloned IRP down the filter chain
> 4. Pends the original IRP
>
> Then,
>
> 5. After the cloned IRP completes, copies the result (and buffer) back to
> the original IRP
> 6. Discards the cloned IRP
> 7. Completes the original IRP
>
> I’m running into a problem when I allocate a buffer for the clone IRP. If
> I allocate NonPagedPool (as all of the minifilter examples do), everything
> works perfectly. However, if I try to allocate PagedPool, I get a bugcheck
> when I try to lock those pages in my AsynchronousIo callback. Here is my
> current order of operations:
>
> In PreOpCallback:
>
> 1. Create a clone IRP and copy the Iopb block from the original.
> 2. Call newBuffer = ExAllocatePoolWithTag(PagedPool, … )
> 3. Call newMdl = IoAllocateMdl(newBuffer, length, FALSE, FALSE, NULL)
> 4. Do NOT call MmBuildMdlForNonPagedPool.
> 5. Send the cloned IRP down using FltPerformAsynchronousIo
>
> Then, in the asynchronous Io callback I try to access the buffer as
> follows:
>
> try
> {
> 1. MmProbeAndLockPages ( … ) <– bugcheck occurs here
> 2. MmGetSystemAddressForMdlSafe( … )
> 3. Copy the buffer
> 4. MmUnlockPages( … )
> }
> except { … }
>
> I’m receiving a bugcheck on MmProbeAndLockPages. Is there something I’m
> forgetting to do? In the documentation for swapping buffers, it says
> “…the buffer can be allocated from either paged or nonpaged pool, and
> the minifilter driver must always create and set an MDL.” Is it enough
> just to allocate the MDL, or is there something else I need to do with it
> before I send it down the filter chain? Is there something I’m forgetting
> to do between allocating the memory on the way down and locking the pages
> on the way up?
>
> My motivation for using paged memory is because NotifyDirectory IRPs can
> potentially live in the bowels of the filesystem for long periods of time
> waiting for something to happen, at which point they are sent back up the
> filter chain. I don’t want to use NonPagedPool and lock pages while my IRP
> is sitting idle.
>
>

What IRQL is the async IO callback running at? It looks like you can’t
MmProbeAndLock pageable addresses at DISPATCH_LEVEL.

“Callers of MmProbeAndLockPages must be running at IRQL <= APC_LEVEL for
pageable addresses, or at IRQL <= DISPATCH_LEVEL for nonpageable
addresses”

http://msdn2.microsoft.com/en-us/library/ms802929.aspx

Massively stupid question: Could anybody explain why you’d want to
MmProbeAndLockPages for a non-pageable address?

~Eric

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Michael Carr
Sent: Tuesday, January 22, 2008 5:22 PM
To: Windows File Systems Devs Interest List
Subject: [ntfsd] sending a cloned IRP down the filter chain

I am trying to write a minifilter that does the following:

  1. Intercept DirectoryControl/NotifyDirectory IRPs 2. Clones the IRP 3.
    Sends the cloned IRP down the filter chain 4. Pends the original IRP

Then,

  1. After the cloned IRP completes, copies the result (and buffer) back
    to the original IRP 6. Discards the cloned IRP 7. Completes the original
    IRP

I’m running into a problem when I allocate a buffer for the clone IRP.
If I allocate NonPagedPool (as all of the minifilter examples do),
everything works perfectly. However, if I try to allocate PagedPool, I
get a bugcheck when I try to lock those pages in my AsynchronousIo
callback. Here is my current order of operations:

In PreOpCallback:

  1. Create a clone IRP and copy the Iopb block from the original.
  2. Call newBuffer = ExAllocatePoolWithTag(PagedPool, … ) 3. Call
    newMdl = IoAllocateMdl(newBuffer, length, FALSE, FALSE, NULL) 4. Do NOT
    call MmBuildMdlForNonPagedPool.
  3. Send the cloned IRP down using FltPerformAsynchronousIo

Then, in the asynchronous Io callback I try to access the buffer as
follows:

try
{

  1. MmProbeAndLockPages ( … ) <– ** bugcheck occurs here **
  2. MmGetSystemAddressForMdlSafe( … )
  3. Copy the buffer
  4. MmUnlockPages( … )
    }
    except { … }

I’m receiving a bugcheck on MmProbeAndLockPages. Is there something I’m
forgetting to do? In the documentation for swapping buffers, it says
“…the buffer can be allocated from either paged or nonpaged pool, and
the minifilter driver must always create and set an MDL.” Is it enough
just to allocate the MDL, or is there something else I need to do with
it before I send it down the filter chain? Is there something I’m
forgetting to do between allocating the memory on the way down and
locking the pages on the way up?

My motivation for using paged memory is because NotifyDirectory IRPs can
potentially live in the bowels of the filesystem for long periods of
time waiting for something to happen, at which point they are sent back
up the filter chain. I don’t want to use NonPagedPool and lock pages
while my IRP is sitting idle.


NTFSD is sponsored by OSR

For our schedule debugging and file system seminars (including our new
fs mini-filter seminar) visit:
http://www.osr.com/seminars

You are currently subscribed to ntfsd as: xxxxx@edsiohio.com To
unsubscribe send a blank email to xxxxx@lists.osr.com

Sorry, I missed that you do not use minifilter design, then your task in
preserving the current design is harder as you can’t use
FltDoCompletionProcessingWhenSafe.


Slava Imameyev, xxxxx@hotmail.com

“Slava Imameyev” wrote in message news:xxxxx@ntfsd…
>> Is there something I’m forgetting to do?
>
> Yes, you forget to ponder your design. What happens if the following code
> is executed at DISPATCH_LEVEL?
>
>> 1. MmProbeAndLockPages ( … ) <– bugcheck occurs here
>> 2. MmGetSystemAddressForMdlSafe( … )
>> 3. Copy the buffer
>> 4. MmUnlockPages( … )
>
> Put the following piece of code before calling MmProbeAndLockPages -
>
> if( KeGetCurrentIrql() == DISPATCH_LEVEL ){
> KeBugCheck( 0xAAAAAAA, 0x0, 0x0, 0x0, 0x0 );
> }
> MmProbeAndLockPages …
>
> Actually, your code with MmProbeAndLockPages at the completion callback(
> i.e. the way up ) looks useless and wrong - why you need to block a buffer
> in the place where it has had to be blocked?
> MDL is used to provide access at high IRQLs to data which might be paged
> out, and this data must have been blocked before IRQL rises.
> If you still want to use this design - then defer completion until it is
> safe by using FltDoCompletionProcessingWhenSafe.
>
> –
> Slava Imameyev, xxxxx@hotmail.com
>
>
> “Michael Carr” wrote in message news:xxxxx@ntfsd…
>>I am trying to write a minifilter that does the following:
>>
>> 1. Intercept DirectoryControl/NotifyDirectory IRPs
>> 2. Clones the IRP
>> 3. Sends the cloned IRP down the filter chain
>> 4. Pends the original IRP
>>
>> Then,
>>
>> 5. After the cloned IRP completes, copies the result (and buffer) back to
>> the original IRP
>> 6. Discards the cloned IRP
>> 7. Completes the original IRP
>>
>> I’m running into a problem when I allocate a buffer for the clone IRP. If
>> I allocate NonPagedPool (as all of the minifilter examples do),
>> everything works perfectly. However, if I try to allocate PagedPool, I
>> get a bugcheck when I try to lock those pages in my AsynchronousIo
>> callback. Here is my current order of operations:
>>
>> In PreOpCallback:
>>
>> 1. Create a clone IRP and copy the Iopb block from the original.
>> 2. Call newBuffer = ExAllocatePoolWithTag(PagedPool, … )
>> 3. Call newMdl = IoAllocateMdl(newBuffer, length, FALSE, FALSE, NULL)
>> 4. Do NOT call MmBuildMdlForNonPagedPool.
>> 5. Send the cloned IRP down using FltPerformAsynchronousIo
>>
>> Then, in the asynchronous Io callback I try to access the buffer as
>> follows:
>>
>> try
>> {
>> 1. MmProbeAndLockPages ( … ) <– bugcheck occurs here
>> 2. MmGetSystemAddressForMdlSafe( … )
>> 3. Copy the buffer
>> 4. MmUnlockPages( … )
>> }
>> except { … }
>>
>> I’m receiving a bugcheck on MmProbeAndLockPages. Is there something I’m
>> forgetting to do? In the documentation for swapping buffers, it says
>> “…the buffer can be allocated from either paged or nonpaged pool, and
>> the minifilter driver must always create and set an MDL.” Is it enough
>> just to allocate the MDL, or is there something else I need to do with it
>> before I send it down the filter chain? Is there something I’m forgetting
>> to do between allocating the memory on the way down and locking the pages
>> on the way up?
>>
>> My motivation for using paged memory is because NotifyDirectory IRPs can
>> potentially live in the bowels of the filesystem for long periods of time
>> waiting for something to happen, at which point they are sent back up the
>> filter chain. I don’t want to use NonPagedPool and lock pages while my
>> IRP is sitting idle.
>>
>>
>
>
>

>> Is there something I’m forgetting to do?

Yes, you forget to ponder your design. What happens if the following code
is executed at DISPATCH_LEVEL?

During this initial stage of development, I have the PAGED_CODE() macro at
the beginning of the asynch callback so I’m guaranteed I can safely use
MmProbeAndLockPages. As I move toward production code I’ll definitely move
those calls into a “safe” function.

Actually, your code with MmProbeAndLockPages at the completion callback(
i.e. the way up ) looks useless and wrong - why you need to block a buffer
in the place where it has had to be blocked?

In the PreOp subroutine I’m allocating paged kernel memory. Don’t I need to
lock it before trying to access it?

MDL is used to provide access at high IRQLs to data which might be paged
out, and this data must have been blocked before IRQL rises.
If you still want to use this design - then defer completion until it is
safe by using FltDoCompletionProcessingWhenSafe.

Since I’ve added PAGED_CODE() at the beginning of the subroutine, I should
be able to lock the memory in the same subroutine, right?

“Slava Imameyev” wrote in message news:xxxxx@ntfsd…
> Sorry, I missed that you do not use minifilter design, then your task in
> preserving the current design is harder as you can’t use
> FltDoCompletionProcessingWhenSafe.

Yes, it is a minifilter design.

“Eric Diven” wrote in message news:xxxxx@ntfsd…
> What IRQL is the async IO callback running at? It looks like you can’t
> MmProbeAndLock pageable addresses at DISPATCH_LEVEL.

I have PAGED_CODE() at the beginning of this subroutine, so it’s running at
IRQL <= APC_LEVEL. Later I’ll move this code into a safe subroutine but I’m
just trying to get this first part to work first. When I step through the
code with a debugger, it has always been IRQL <= APC_LEVEL so far.

> Massively stupid question: Could anybody explain why you’d want to
> MmProbeAndLockPages for a non-pageable address?

I’m trying to use pageable memory because my IRP will potentially be pended
by lower altitude filters for long periods of time, so I call
ExAllocatePoolWithTag(PagedPool, … ) in the PreOpCallback. That’s why I’m
trying to lock it in my asynch callback.

> Since I’ve added PAGED_CODE() at the beginning of the subroutine, I
should be able to lock the memory in the same subroutine, right?

Calling PAGED_CODE is going to move your bugcheck on a checked build,
not solve it. Provided the system doesn’t bugcheck at the PAGED_CODE()
call, you can MmProbeAndLockPages (), but you’ll still see the system
crash at the PAGED_CODE () call when it’s running at DISPATCH_LEVEL.

In the PreOp subroutine I’m allocating paged kernel memory. Don’t I
need to lock it before trying to access it?

Yes, but if you’re executing at DISPATCH_LEVEL, and you try to
MmProbeAndLockPages (), and the memory isn’t resident, there’s no
possible way for it to become resident. It can’t be paged in at that
level, so either it needs to be locked BEFORE your async callback is
called (by locking it in the preop, which makes it sort of moot to
allocate from the PagedPool), or you need to ensure that your callback
is running at a safe level (which obviates calling MmProbeAndLockPages
() at all).

~Eric

> When I step through the code with a debugger, it has always been IRQL
<= APC_LEVEL so far.

Well, without knowing any more about the bugcheck you’re getting, we’ve
all assumed that it’s an IRQL problem. When you get a bugcheck try a
!irql in the debugger and see if it really is running at <=APC_LEVEL.
Also, make friends with !analyze -v, and possibly post some output if
you can’t figure it out yourself.

> Massively stupid question: Could anybody explain why you’d want to
> MmProbeAndLockPages for a non-pageable address?

I’m trying to use pageable memory because my IRP will potentially be
pended by lower altitude filters for long periods of time, so I call
ExAllocatePoolWithTag(PagedPool, … ) in the PreOpCallback. That’s why
I’m trying to lock it in my asynch callback.

You’ve missed the point of the question. If the MDL describes a
non-pageable address, MmProbeAndLockPages should be completely
redundant, unless I’ve misinterpreted the docs and their usage of the
phrase “non-pageable address”.

~Eric


NTFSD is sponsored by OSR

For our schedule debugging and file system seminars (including our new
fs mini-filter seminar) visit:
http://www.osr.com/seminars

You are currently subscribed to ntfsd as: xxxxx@edsiohio.com To
unsubscribe send a blank email to xxxxx@lists.osr.com

WRONG. PAGED_CODE() doesn’t do anything other than assert that the current
IRQL is less than dispatch level. And does nothing at all if you are running
your release build drivers. It will bugcheck your driver if it gets executed
at dispatch level.

On Jan 23, 2008 10:28 AM, Michael Carr wrote:

> >> Is there something I’m forgetting to do?
> > Yes, you forget to ponder your design. What happens if the following
> code
> > is executed at DISPATCH_LEVEL?
>
> During this initial stage of development, I have the PAGED_CODE() macro at
> the beginning of the asynch callback so I’m guaranteed I can safely use
> MmProbeAndLockPages. As I move toward production code I’ll definitely move
> those calls into a “safe” function.
>
> > Actually, your code with MmProbeAndLockPages at the completion callback(
> > i.e. the way up ) looks useless and wrong - why you need to block a
> buffer
> > in the place where it has had to be blocked?
>
> In the PreOp subroutine I’m allocating paged kernel memory. Don’t I need
> to
> lock it before trying to access it?
>
> > MDL is used to provide access at high IRQLs to data which might be paged
> > out, and this data must have been blocked before IRQL rises.
> > If you still want to use this design - then defer completion until it is
> > safe by using FltDoCompletionProcessingWhenSafe.
>
> Since I’ve added PAGED_CODE() at the beginning of the subroutine, I should
> be able to lock the memory in the same subroutine, right?
>
>
> —
> NTFSD is sponsored by OSR
>
> For our schedule debugging and file system seminars
> (including our new fs mini-filter seminar) visit:
> http://www.osr.com/seminars
>
> You are currently subscribed to ntfsd as: xxxxx@hollistech.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>


Mark Roddy

“Eric Diven” wrote in message news:xxxxx@ntfsd…
>> When I step through the code with a debugger, it has always been IRQL
<= APC_LEVEL so far.

>Well, without knowing any more about the bugcheck you’re getting, we’ve
>all assumed that it’s an IRQL problem. When you get a bugcheck try a
>!irql in the debugger and see if it really is running at <=APC_LEVEL.
>Also, make friends with !analyze -v, and possibly post some output if
>you can’t figure it out yourself.

Thanks I’ll give that a try right now.

>>> Massively stupid question: Could anybody explain why you’d want to
>>> MmProbeAndLockPages for a non-pageable address?
>> I’m trying to use pageable memory because my IRP will potentially be
>>pended by lower altitude filters for long periods of time, so I call
>>ExAllocatePoolWithTag(PagedPool, … ) in the PreOpCallback. That’s why
>>I’m trying to lock it in my asynch callback.
>You’ve missed the point of the question. If the MDL describes a
>non-pageable address, MmProbeAndLockPages should be completely
>redundant, unless I’ve misinterpreted the docs and their usage of the
>phrase “non-pageable address”.

I don’t see anything in the documentation that says an MDL describes a
non-pageable address. From the topic “Using MDLs” it says “The system uses a
memory descriptor list (MDL) structure to represent the physical page layout
for a virtual memory buffer.” Then further down it says “For pagable memory,
the correspondence between virtual and physical memory is temporary, so the
page number array is valid only under certain circumstances. Call
MmProbeAndLockPages to lock the pagable memory into place and initialize the
page number array for the current layout.” The MmProbeAndLockPages command,
as its output, updates an MDL (which must be pre-allocated) that describes
the physical layout of the now-locked buffer. Maybe we’re both arguing the
same point, although I think it’s important to semantically distinguish
between a “non-pageable” address (what you’re referring to) and a “locked
pageable” address (what I’m referring to).

“Mark Roddy” wrote in message news:xxxxx@ntfsd…
WRONG. PAGED_CODE() doesn’t do anything other than assert that the current
IRQL is less than dispatch level. And does nothing at all if you are running
your release build drivers. It will bugcheck your driver if it gets executed
at dispatch level.

Yes, I realize this, in fact that’s what I’m counting on. I’m simply using
it during this very early development stage to verify to myself that my
asynch callback happens to be running at IRQL <= APC_LEVEL, and so far it
has been. In my production code I will remove PAGED_CODE from the aynch
callback, do the proper IRQL checking, and move any pageable code into its
own safe subroutine. But so far, during debug sessions I haven’t had
PAGED_CODE cause a bugcheck.

The PAGED_CODE macro does not work if you build with WDK6000 and test under
XP. It will output a message to the debugger but will not ASSERT.

Bill Wandel

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Michael Carr
Sent: Wednesday, January 23, 2008 11:24 AM
To: Windows File Systems Devs Interest List
Subject: Re:[ntfsd] sending a cloned IRP down the filter chain

“Mark Roddy” wrote in message news:xxxxx@ntfsd…
WRONG. PAGED_CODE() doesn’t do anything other than assert that the current
IRQL is less than dispatch level. And does nothing at all if you are running
your release build drivers. It will bugcheck your driver if it gets executed
at dispatch level.

Yes, I realize this, in fact that’s what I’m counting on. I’m simply using
it during this very early development stage to verify to myself that my
asynch callback happens to be running at IRQL <= APC_LEVEL, and so far it
has been. In my production code I will remove PAGED_CODE from the aynch
callback, do the proper IRQL checking, and move any pageable code into its
own safe subroutine. But so far, during debug sessions I haven’t had
PAGED_CODE cause a bugcheck.


NTFSD is sponsored by OSR

For our schedule debugging and file system seminars (including our new fs
mini-filter seminar) visit:
http://www.osr.com/seminars

You are currently subscribed to ntfsd as: xxxxx@bwandel.com To
unsubscribe send a blank email to xxxxx@lists.osr.com

“Bill Wandel” wrote in message news:xxxxx@ntfsd…
> The PAGED_CODE macro does not work if you build with WDK6000 and test
> under
> XP. It will output a message to the debugger but will not ASSERT.

Hmm, good to know. I’m running on Vista … same problem there? Just now I
checked NTFSD, the docs, and in Google but didn’t see any mention of this
problem.

Thanks,
Mike

I am pretty sure that it works under Vista.
I posted about this a couple of months ago to the ntdev list.

Bill Wandel

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Michael Carr
Sent: Wednesday, January 23, 2008 12:34 PM
To: Windows File Systems Devs Interest List
Subject: Re:[ntfsd] sending a cloned IRP down the filter chain

“Bill Wandel” wrote in message news:xxxxx@ntfsd…
> The PAGED_CODE macro does not work if you build with WDK6000 and test
> under XP. It will output a message to the debugger but will not
> ASSERT.

Hmm, good to know. I’m running on Vista … same problem there? Just now I
checked NTFSD, the docs, and in Google but didn’t see any mention of this
problem.

Thanks,
Mike


NTFSD is sponsored by OSR

For our schedule debugging and file system seminars (including our new fs
mini-filter seminar) visit:
http://www.osr.com/seminars

You are currently subscribed to ntfsd as: xxxxx@bwandel.com To
unsubscribe send a blank email to xxxxx@lists.osr.com

>>> Massively stupid question: Could anybody explain why you’d want to

>> MmProbeAndLockPages for a non-pageable address?
> I’m trying to use pageable memory because my IRP will potentially be
>pended by lower altitude filters for long periods of time, so I call
>ExAllocatePoolWithTag(PagedPool, … ) in the PreOpCallback. That’s
>why I’m trying to lock it in my asynch callback.
You’ve missed the point of the question. If the MDL describes a
non-pageable address, MmProbeAndLockPages should be completely
redundant, unless I’ve misinterpreted the docs and their usage of the
phrase “non-pageable address”.

I don’t see anything in the documentation that says an MDL describes a
non-pageable address.

It can describe either paged memory or non-paged memory.

From the topic “Using MDLs” it says “The system uses a memory
descriptor list (MDL) structure to represent the physical page layout
for a virtual memory buffer.” Then further down it says “For pagable
memory, the correspondence between virtual and physical memory is
temporary, so the page number array is valid only under certain
circumstances. Call MmProbeAndLockPages to lock the pagable memory into
place and initialize the page number array for the current layout.” The
MmProbeAndLockPages command, as its output, updates an MDL (which must
be pre-allocated) that describes the physical layout of the now-locked
buffer.

We’re in agreement on this point, but the MmPALP docs also say: “Callers
of MmProbeAndLockPages must be running at IRQL <= APC_LEVEL for pageable
addresses, or at IRQL <= DISPATCH_LEVEL for nonpageable addresses.”

Maybe we’re both arguing the same point, although I think it’s
important to semantically distinguish between a “non-pageable” address
(what you’re referring to) and a “locked pageable” address (what I’m
referring to).

It is important to distinguish between the two, but you have neither of
these things in your async callback. You have an MDL that describes
unlocked pageable memory.

Let’s back up a second here and take a look at three scenarios:

I:

  1. malloc a buffer from the paged pool at APC_LEVEL or PASSIVE_LEVEL
  2. Get an MDL for it
  3. In the blink of an eye your buffer gets paged out.
  4. you find yourself at DISPATCH_LEVEL with this MDL which describes
    memory that is no longer paged in.
  5. MmPALP… ()
  6. Bugcheck! The memory described by the MDL is paged memory and it
    can’t be paged back in because of IRQL

II:

  1. malloc a buffer from the non-paged pool at <= DISPATCH_LEVEL
  2. Get an MDL for it
  3. War breaks out
  4. years pass, this discussion fades from memory. Incredibly, your
    computer stays up the whole time.
  5. You rediscover your computer and find yourself at DISPATCH_LEVEL.
  6. MmPALP… () (whether or not this serves any purpose was my original
    question)
  7. it works, because the memory still hasn’t been paged out, and never
    will be.

III:

  1. malloc a buffer from the paged pool at APC_LEVEL or PASSIVE_LEVEL
  2. Get an MDL for it
  3. MmPALP ()
  4. You’re abducted by aliens
  5. years pass, this discussion fades from memory. Incredibly, your
    computer stays up the whole time.
  6. The aliens return you and you rediscover your computer and find
    yourself at DISPATCH_LEVEL.
  7. MmPALP… () (redundantly, though you still have to make a matched
    call to unlock the memory)
  8. it works, because the memory still hasn’t been paged out (because
    it’s locked), and won’t be until you allow it to be.

Situation I is (maybe) what you’re seeing happen.
Situation II is what the sample code with the WDK does.
Situation III is the other possible situation where you can access the
memory in your async callback without getting yourself to either
PASSIVE_LEVEL or APC_LEVEL.

The point is that the mdl describes a buffer allocated from the paged
pool, and that buffer hasn’t been locked when you were at PASSIVE_LEVEL
or APC_LEVEL, you’re not going to be able to lock it at DISPATCH_LEVEL.
If the pages are locked at PASSIVE or APC, then the MDL will still be
useful at DISPATCH, and is just as good as an MDL describing memory from
the non-paged pool.


NTFSD is sponsored by OSR

For our schedule debugging and file system seminars (including our new
fs mini-filter seminar) visit:
http://www.osr.com/seminars

You are currently subscribed to ntfsd as: xxxxx@edsiohio.com To
unsubscribe send a blank email to xxxxx@lists.osr.com

“Eric Diven” wrote in message news:xxxxx@ntfsd…

>>I don’t see anything in the documentation that says an MDL describes a
>>non-pageable address.

>We’re in agreement on this point, but the MmPALP docs also say: “Callers
>of MmProbeAndLockPages must be running at IRQL <= APC_LEVEL for pageable
>addresses, or at IRQL <= DISPATCH_LEVEL for nonpageable addresses.”

I guess I’ve been temporarily disregarding IRQL issues because my callbacks
are all running at IRQL <= APC_LEVEL, otherwise I would be receiving
bugchecks from my PAGED_CODE() macros, which I’m not. I ran the !irql windbg
command as you suggested and the IRQL level was 0 in all test cases so far.

>Let’s back up a second here and take a look at three scenarios:
>1) malloc a buffer from the paged pool at APC_LEVEL or PASSIVE_LEVEL
>2) Get an MDL for it
>3) In the blink of an eye your buffer gets paged out.
>4) you find yourself at DISPATCH_LEVEL with this MDL which describes
>memory that is no longer paged in.
>5) MmPALP… ()
>6) Bugcheck! The memory described by the MDL is paged memory and it
>can’t be paged back in because of IRQL

This is the scenario I’m going for, except more like this for the moment:

1. PreOp callback gets called
2. Execute PAGED_CODE() to check and verify that I happen to be randomly and
luckily be called at IRQL <= APC_LEVEL. This is for early-phase
quick-and-dirty prototyping purposes and will be changed later for more
rigorous handling.
3. Malloc a buffer from paged pool
4. Get an MDL for it
5. Call FltPerformAsynchronousIo

6. Take a cruise to bahamas

7. Asynronous callback gets called
8. Execute PAGED_CODE() again to verify that the operating system welcomed
me back from my vacation by calling me with IRQL <= APC_LEVEL
9. MmPALP
10. It works because both the PreOpCallback and the AsynchCallback were
called at IRQL <= APC_LEVEL, as evidenced by the fact that I didn’t get any
bugchecks from the PAGED_CODE() macros.

So far, steps 1 - 8 seem to be executing just fine. Step 9 dies.

>1) malloc a buffer from the non-paged pool at <= DISPATCH_LEVEL
>2) Get an MDL for it
>3) War breaks out
>4) years pass, this discussion fades from memory. Incredibly, your
>computer stays up the whole time.
>5) You rediscover your computer and find yourself at DISPATCH_LEVEL.
>6) MmPALP… () (whether or not this serves any purpose was my original
>question)
>7) it works, because the memory still hasn’t been paged out, and never
>will be.

This scenario works 100% perfectly (I’ve tried it) but is unsuitable because
it locks the buffer for long periods of time.

>1) malloc a buffer from the paged pool at APC_LEVEL or PASSIVE_LEVEL
>2) Get an MDL for it
>3) MmPALP ()
>4) You’re abducted by aliens
>5) years pass, this discussion fades from memory. Incredibly, your
>computer stays up the whole time.
>6) The aliens return you and you rediscover your computer and find
>yourself at DISPATCH_LEVEL.
>7) MmPALP… () (redundantly, though you still have to make a matched
>call to unlock the memory)
>8) it works, because the memory still hasn’t been paged out (because
>it’s locked), and won’t be until you allow it to be.

This scenario also locks the buffer for long periods of time.

Some things I’ve tried this afternoon:

1. Switched MmProbeAndLockPages to FltLockUserBuffer. This worked perfectly,
and I could see the buffer contents correctly, but then in later tests with
the same code the filesystem started issuing a bugcheck prior to the asych
callback. It began reporting a memory corruption error when a lower altitude
filter was calling FsRtlNotifyFilterReportChange. So I turned my attention
back to the PreOp callback and how I was allocating the memory in the first
place…

2. In the PreOp callback I removed the IoAllocateMdl and instead set
MdlAddress = NULL in the FLT_CALLBACK_DATA structure. This actually worked
perfectly all the way through, except when I locked the buffer in the asynch
callback and viewed the result, I only had junk.

3. I re-inserted the IoAllocateMdl and added a call to MmInitializeMdl since
it is unclear from the docs whether I need to initialize the Mdl structure
after I allocate pageable memory. In the debugger I observed that
MmInitializeMdl sets the Mdl’s Flags property to 0 but does nothing else
that I can see. With this approach I again began receiving the bugchecks
from FRNFRC as in #1 above.

I’ll keep you posted on any exciting new developments, including any alien
abductions.

“Michael Carr” wrote in message news:xxxxx@ntfsd…
> I’m running into a problem when I allocate a buffer for the clone IRP. If
> I allocate NonPagedPool (as all of the minifilter examples do), everything
> works perfectly. However, if I try to allocate PagedPool, I get a bugcheck
> when I try to lock those pages in my AsynchronousIo callback.

Ok, I think I’ve finally determined that I’m trying to do the impossible.
According to the “Determining the Buffering Method for an I/O Operation”
only the following methods are supported (I had read these before but not
closely enough):

Buffered I/O :
I/O manager provides a system-space buffer from non-paged memory
(this works I’ve tried it)

Direct I/O :
I/O manager probes and locks the user-space buffer, then provides an MDL
describing the user buffer
(this works I’ve tried it)

Nether Buffered nor Direct I/O :
I/O manager passes a user-space buffer virtual address directly to the file
system stack.
(this works, although for some odd reason I can’t see the data when it comes
back up the chain)

Basically, these three choices don’t leave the door open for system buffers
from paged memory… which probably explains why it doesn’t seem to work.
So, it’s time to give up and just use a nonpaged system-space buffer and
move on with my life.

You don’t ever want to disregard IRQL issues, even temporarily, because
they massively influence the design of a driver. If they don’t, or if
they are untested, you’re almost certainly in for some very unwelcome
surprises.

Good luck,

mm

Michael Carr wrote:

“Eric Diven” wrote in message news:xxxxx@ntfsd…
>
>>> I don’t see anything in the documentation that says an MDL describes a
>>> non-pageable address.
>
>> We’re in agreement on this point, but the MmPALP docs also say: “Callers
>> of MmProbeAndLockPages must be running at IRQL <= APC_LEVEL for pageable
>> addresses, or at IRQL <= DISPATCH_LEVEL for nonpageable addresses.”
>
> I guess I’ve been temporarily disregarding IRQL issues because my
> callbacks are all running at IRQL <= APC_LEVEL, otherwise I would be
> receiving bugchecks from my PAGED_CODE() macros, which I’m not. I ran
> the !irql windbg command as you suggested and the IRQL level was 0 in
> all test cases so far.
>
>> Let’s back up a second here and take a look at three scenarios:
>> 1) malloc a buffer from the paged pool at APC_LEVEL or PASSIVE_LEVEL
>> 2) Get an MDL for it
>> 3) In the blink of an eye your buffer gets paged out.
>> 4) you find yourself at DISPATCH_LEVEL with this MDL which describes
>> memory that is no longer paged in.
>> 5) MmPALP… ()
>> 6) Bugcheck! The memory described by the MDL is paged memory and it
>> can’t be paged back in because of IRQL
>
> This is the scenario I’m going for, except more like this for the moment:
>
> 1. PreOp callback gets called
> 2. Execute PAGED_CODE() to check and verify that I happen to be randomly
> and luckily be called at IRQL <= APC_LEVEL. This is for early-phase
> quick-and-dirty prototyping purposes and will be changed later for more
> rigorous handling.
> 3. Malloc a buffer from paged pool
> 4. Get an MDL for it
> 5. Call FltPerformAsynchronousIo
>
> 6. Take a cruise to bahamas
>
> 7. Asynronous callback gets called
> 8. Execute PAGED_CODE() again to verify that the operating system
> welcomed me back from my vacation by calling me with IRQL <= APC_LEVEL
> 9. MmPALP
> 10. It works because both the PreOpCallback and the AsynchCallback were
> called at IRQL <= APC_LEVEL, as evidenced by the fact that I didn’t get
> any bugchecks from the PAGED_CODE() macros.
>
> So far, steps 1 - 8 seem to be executing just fine. Step 9 dies.
>
>> 1) malloc a buffer from the non-paged pool at <= DISPATCH_LEVEL
>> 2) Get an MDL for it
>> 3) War breaks out
>> 4) years pass, this discussion fades from memory. Incredibly, your
>> computer stays up the whole time.
>> 5) You rediscover your computer and find yourself at DISPATCH_LEVEL.
>> 6) MmPALP… () (whether or not this serves any purpose was my original
>> question)
>> 7) it works, because the memory still hasn’t been paged out, and never
>> will be.
>
> This scenario works 100% perfectly (I’ve tried it) but is unsuitable
> because it locks the buffer for long periods of time.
>
>> 1) malloc a buffer from the paged pool at APC_LEVEL or PASSIVE_LEVEL
>> 2) Get an MDL for it
>> 3) MmPALP ()
>> 4) You’re abducted by aliens
>> 5) years pass, this discussion fades from memory. Incredibly, your
>> computer stays up the whole time.
>> 6) The aliens return you and you rediscover your computer and find
>> yourself at DISPATCH_LEVEL.
>> 7) MmPALP… () (redundantly, though you still have to make a matched
>> call to unlock the memory)
>> 8) it works, because the memory still hasn’t been paged out (because
>> it’s locked), and won’t be until you allow it to be.
>
> This scenario also locks the buffer for long periods of time.
>
> Some things I’ve tried this afternoon:
>
> 1. Switched MmProbeAndLockPages to FltLockUserBuffer. This worked
> perfectly, and I could see the buffer contents correctly, but then in
> later tests with the same code the filesystem started issuing a bugcheck
> prior to the asych callback. It began reporting a memory corruption
> error when a lower altitude filter was calling
> FsRtlNotifyFilterReportChange. So I turned my attention back to the
> PreOp callback and how I was allocating the memory in the first place…
>
> 2. In the PreOp callback I removed the IoAllocateMdl and instead set
> MdlAddress = NULL in the FLT_CALLBACK_DATA structure. This actually
> worked perfectly all the way through, except when I locked the buffer in
> the asynch callback and viewed the result, I only had junk.
>
> 3. I re-inserted the IoAllocateMdl and added a call to MmInitializeMdl
> since it is unclear from the docs whether I need to initialize the Mdl
> structure after I allocate pageable memory. In the debugger I observed
> that MmInitializeMdl sets the Mdl’s Flags property to 0 but does nothing
> else that I can see. With this approach I again began receiving the
> bugchecks from FRNFRC as in #1 above.
>
> I’ll keep you posted on any exciting new developments, including any
> alien abductions.
>
>