When to use what: FltPerformSynchronousIo & FltPerformAsynchronousIo?

I am now totally confused.

Ok. Let me explain what I meant.

When, I get some IRP ( Callbackdata ) in my PreCallback routine ( say paging
write ), and I issue a request to read/ query the same file by building a
callback data using FltAllocateCallbackData and then sending it using
FltPerformAsynchronousIo. This is what I wanted to do using, the sequence of
steps that i had posted before. All that i want to ensure is that, the
reading/ querying is done before the actual paging write happens. How do i
ensure that?

Is this also not possible?

I think i am confused about the whole concept of TopLevelIrp and Paging I/O
.

May be its an easy concept, but as a beginner i am not able to understand it
and its implications very well.

  1. Slava, can you please explain me in detail, why this will fail.

  2. What is the alternate way of doing the stuff?

  3. You mentioned that the set of calls that can be made are limited. What
    are those calls?

Ok Slava…
So, does this mean that it is safe to issue requests to the same data stream
( using the same file object ).
But issuing requests to other data stream can lead into deadlocks, even if
it is a noncached request.

Kindly reply to the previous posting too, in the same thread. I have asked
some queries.

----- Original Message -----
From: “Slava Imameyev”
Newsgroups: ntfsd
To: “Windows File Systems Devs Interest List”
Sent: Thursday, July 26, 2007 4:24 PM
Subject: Re:[ntfsd] Re:When to use what: FltPerformSynchronousIo &
FltPerformAsynchronousIo?

>
> > AFAIK, TopLevelIrp is used as a locking hierarchy
>> between FSD, Cache Manager and Memeory Manager.
>> But if i use Non Cached I/O, as mentioned by Ayush, should this be a
>> problem?
>
> Your might face problems with FSD’s lock hierarchy if you issue requests
> to FSD when TopLevelIrp is not NULL. If you issue a request( especially
> non-paging ) to FSD when TopLevelIrp is not NULL then you should be ready
> to deal with deadlocks, because you might violate the FSD’s lock
> hierarchy. The most dangerous thing is to issue a request for a data
> stream different from those used for the original request( i.e. the paging
> write request in your case ).
>
> –
> Slava Imameyev, xxxxx@hotmail.com
>
>
>
> “Kernel Developer” wrote in message
> news:xxxxx@ntfsd…
>> Slava, you mentioned that:
>> “Because there is a strong possibility( nearly 100%) that some resources
>> of the
>> FSD driver have been already acquired thus a set of allowed requests has
>> been
>> reduced because of a possible deadlock in the FSD driver( this set
>> strongly
>> depends on FSD ).”
>>
>> I am new in this field and AFAIK, TopLevelIrp is used as a locking
>> hierarchy between FSD, Cache Manager and Memeory Manager.
>> But if i use Non Cached I/O, as mentioned by Ayush, should this be a
>> problem?
>> Also, what are the limited calls that i can make?
>>
>
>
>
> —
> NTDEV 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@yahoo.co.in
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>

>All that i want to ensure is that, the reading/ querying is done before the

actual paging write happens.

If you want to know whether this might violate the lock hierarchy, then the
answer is Yes, though it might work for many modern FSDs. Actually, I’ve
never done such thing because its deadlock pron pattern, so I only try to
guess consequences.

Is this also not possible?

It is possible, but you’ve been warned.

I think i am confused about the whole concept of TopLevelIrp and Paging
I/O

The conception is VERY SIMPLE. I’ll try to explain it.
In case of paging IO Memory Manager(MM) is an FSD client, while in other
cases this is a user application who is FSD client.
But FSD is itself a Memory Manager client(!), let’s forget here about Cache
Manager( who is a Memory Manager client and FSD is a Cache Manager client ).
It is obvious that both FSD and Memory Manager have some synchronization
primitives, let’s use “FsdSync” for FSD’s synchronization resources and
“MmSync” for Memory Manager’s synchronization resources .
So, then a user application calls FSD the synchronization resources are
acquired in the following sequence FsdSync-MmSync , remember that Fsd is a
Memory Manager client.
When Memory Managers wants to flush dirty pages it becames the FSD
client(!), but before issuing a PAGING write request Memory Manager should
acquire MmSync resources to maintain its internal synchronization, so after
calling the FSD the following lock sequence might have place MmSync-FsdSync.
So, in the case of user application the sequence is FsdSync-MmSync but in
the case of dirty pages flushing( i.e. paging write ) the sequence is
MmSync-FsdSync, as you know this will result in a deadlock. For avoid this
problem FSD callbacks are used by Memory Manager to call FSD before
acquiring its(Memory Manager’s) synchronization resources, so FSD has an
opportunity to preserve the lock hierarchy and acquire its(FSD’s)
synchronization resources before Memory Manager acquires its(MM’s) resources
and FSD does this and thread’s TopLevelIrp is set in this case to a some
value.

  1. Slava, can you please explain me in detail, why this will fail.

This won’t fail, this might deadlock the system.

  1. What is the alternate way of doing the stuff?

Sorry, this question requires more thorough investigation. May be you should
redesign your software architecture. But I am sure that generating read
request on a paging write path when ToplevelIrp is not NULL is dangerous.

  1. You mentioned that the set of calls that can be made are limited. What
    are those calls?

Depends on FSD. There is no answer suitable for all FSDs. Test your filter
driver with all available FSDs.


Slava Imameyev, xxxxx@hotmail.com

“Kernel Developer” wrote in message
news:xxxxx@ntfsd…
>I am now totally confused.
>
> Ok. Let me explain what I meant.
>
> When, I get some IRP ( Callbackdata ) in my PreCallback routine ( say
> paging write ), and I issue a request to read/ query the same file by
> building a callback data using FltAllocateCallbackData and then sending it
> using FltPerformAsynchronousIo. This is what I wanted to do using, the
> sequence of steps that i had posted before. All that i want to ensure is
> that, the reading/ querying is done before the actual paging write
> happens. How do i ensure that?
>
>
>
> Is this also not possible?
>
>
>
> I think i am confused about the whole concept of TopLevelIrp and Paging
> I/O .
>
> May be its an easy concept, but as a beginner i am not able to understand
> it and its implications very well.
>
>
>
> 1. Slava, can you please explain me in detail, why this will fail.
>
> 2. What is the alternate way of doing the stuff?
>
> 3. You mentioned that the set of calls that can be made are limited. What
> are those calls?
>
>
>
>

I don’t know what the conclusion of this thread is, but I got to know
something very interesting & contradicting…

As per the documentation of FltPerformAsynchronousIo,

“The caller of FltPerformAsynchronousIo can be running at IRQL <= APC_LEVEL
if the IRP_PAGING_IO flag is set in the IrpFlags member of the
FLT_IO_PARAMETER_BLOCK structure for the operation. (This flag is only valid
for IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_QUERY_INFORMATION, and
IRP_MJ_SET_INFORMATION operations.) Otherwise, the caller must be running at
IRQL PASSIVE_LEVEL.”

Which I think means that it can be used in Paging I/O path.

Referring to the section “Dispatch Routine IRQL and Thread Context” of the
WDK, I see that all paging I/O calls come at IRQL = APC_LEVEL.

Referring to the points mentioned by Slava, mostly ( almost 100% ) of these
( paging I/O ) calls have TopLevelIrp != NULL and issuing File System calls
in this scenario can be dangerous.

So, now we have a function named FltPerformAsynchronousIo which can be used
in paging i/o path at IRQL<= APC_LEVEL, but should not be used because
almost all paging i/o calls come with TopLevelIrp != NULL.

So, is the function of no use? Or am I using a wrong logic to conclude this?
Someone please clarify ( Slava, Maxim, Tony, Peter V., anyone? ).

I don’t have much experience and didn’t ever encounter any such thing in any
of my minifilters… ( Because monitoring and manipulating IRP with
IRP_PAGING_IO flag was never required )…
I think this is what Experience means…
Would someone be kind enough to enlighten me and the query poster?

Regards!
Ayush Gupta

I think I understand your confusion!

“The caller of FltPerformAsynchronousIo can be running at IRQL <=
APC_LEVEL
if the IRP_PAGING_IO flag is set in the IrpFlags member of the
FLT_IO_PARAMETER_BLOCK structure for the operation. (This flag is only
valid
for IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_QUERY_INFORMATION, and
IRP_MJ_SET_INFORMATION operations.) Otherwise, the caller must be running
at
IRQL PASSIVE_LEVEL.”

This is a parameter description for FltPerformAsynchronousIo. Let’s rephrase
it to reveal the role of the IRP_PAGING_IO flag - it says that if the
CALLER of FltPerformAsynchronousIo is now running at APC_LEVEL the Irp CAN
BE COMPLETED safely only if IRP_PAGING_IO flag is set for the operation(
the first parameter for FltPerformAsynchronousIo), and this is TRUE because
if the request is processed synchronously(!) it will be impossible to
complete a non-paging Irp at APC_LEVEL( using the standard completion with
APC but not returning STATUS_MORE_PROCESSING_REQUIRED ) because APCs
delivering are blocked, but some paging Irp has special processing w/o APC.

Referring to the points mentioned by Slava, mostly ( almost 100% ) of
these
( paging I/O ) calls have TopLevelIrp != NULL and issuing File System
calls
in this scenario can be dangerous.

This is a description of the request received by the caller but not sent by
FltPerformAsynchronousIo. Actually, the author of this topic wants to send a
READ request when he receives a PAGING WRITE request!
So, the discussion is around issuing a read request on a paging write path
with non NULL TopLevelIrp.
We do not discuss here the merits of FltPerformAsynchronousIo.


Slava Imameyev, xxxxx@hotmail.com

“Ayush Gupta” wrote in message news:xxxxx@ntfsd…
>I don’t know what the conclusion of this thread is, but I got to know
> something very interesting & contradicting…
>
> As per the documentation of FltPerformAsynchronousIo,
>
> “The caller of FltPerformAsynchronousIo can be running at IRQL <=
> APC_LEVEL
> if the IRP_PAGING_IO flag is set in the IrpFlags member of the
> FLT_IO_PARAMETER_BLOCK structure for the operation. (This flag is only
> valid
> for IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_QUERY_INFORMATION, and
> IRP_MJ_SET_INFORMATION operations.) Otherwise, the caller must be running
> at
> IRQL PASSIVE_LEVEL.”
>
> Which I think means that it can be used in Paging I/O path.
>
> Referring to the section “Dispatch Routine IRQL and Thread Context” of the
> WDK, I see that all paging I/O calls come at IRQL = APC_LEVEL.
>
> Referring to the points mentioned by Slava, mostly ( almost 100% ) of
> these
> ( paging I/O ) calls have TopLevelIrp != NULL and issuing File System
> calls
> in this scenario can be dangerous.
>
> So, now we have a function named FltPerformAsynchronousIo which can be
> used
> in paging i/o path at IRQL<= APC_LEVEL, but should not be used because
> almost all paging i/o calls come with TopLevelIrp != NULL.
>
> So, is the function of no use? Or am I using a wrong logic to conclude
> this?
> Someone please clarify ( Slava, Maxim, Tony, Peter V., anyone? ).
>
> I don’t have much experience and didn’t ever encounter any such thing in
> any
> of my minifilters… ( Because monitoring and manipulating IRP with
> IRP_PAGING_IO flag was never required )…
> I think this is what Experience means…
> Would someone be kind enough to enlighten me and the query poster?
>
> Regards!
> Ayush Gupta
>
>

Ha… That makes sense…
That even clarified my doubts a lot.
Now, just one more question. Leave the Reading of the file…

>>Can I use FltPerformAsynchronousIo to QUERY THE FILE SIZE of the file for
>>which i have received the paging write?

Actually I want to find out whether a particular write request ( even a
paging write ) to a file is on the last page present on the file?
I have read in some thread on the forum that the EOF is actually extended
not by the paging write operation, but rather, a SET INFO IRP is sent by the
Cache manager ( AM I CORRECT HERE? ) to extend the EOF to accomodate the
buffer that is present in the page. And this SET INFO IRP is sent before the
actual paging write comes.
So, now back to the original question:

  1. Can I use FltPerformAsynchronousIo to QUERY THE FILE SIZE ( EOF ) in the
    paging write path?
  2. If i cannot use FltPerformAsynchronousIo, how can i come to know the EOF
    when i receive a paging write, and find out whether it is the last page.

I WANT TO DO ALL THIS IN PRECALLBACK ITSELF. I CANNOT WAIT TILL
POSTCALLBACK.

Thanks!
-K. Dev.

> Is it fine to call FltPerformAsynchronousIo in a pre paging write callback

and then wait for an object using KeWaitForSingleObject.

No. Blocking in paging IO paths is a bad idea.

I personally would try to escape from FltMgr’s framework, use IoAllocateIrp for
my operation, fill this IRP, set the original paging write IRP as the
completion context, and submit my IRP down.

The competion routine would destroy this IRP and then submit the original
paging write IRP (completion context) down.

This is 100% async and weakens the deadlock potential a lot.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Thanks Maxim!

I personally would try to escape from FltMgr’s framework, use
IoAllocateIrp for
my operation, fill this IRP, set the original paging write IRP as the
completion context, and submit my IRP down.

Are you proposing to replace the original IRP with the new IRP and send the
New IRP instead of the Original IRP?
From the completion routine, send the original IRP for processing…
Right?

But i am using Filter Manager’s framework.
So, whats the equivalent of your solution for this framework?

And could you also reply to Message 27 of the same thread?

Thanks!

“Kernel Developer” wrote in message
news:xxxxx@ntfsd…
> Thanks Maxim!
>
>
>> I personally would try to escape from FltMgr’s framework, use
>> IoAllocateIrp for
>> my operation, fill this IRP, set the original paging write IRP as the
>> completion context, and submit my IRP down.
>
> Are you proposing to replace the original IRP with the new IRP and send
> the New IRP instead of the Original IRP?
> From the completion routine, send the original IRP for processing…
> Right?

The problem here is that the IRP either has to be sent through the whole
stack (including your minifilter) or the call will bypass any lower
mini-filters. Since there is no way to that I know of (if I am wrong I
would be happy to hear how), to pass the IRP to the next filter.


Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

> Are you proposing to replace the original IRP with the new IRP and send the

New IRP instead of the Original IRP?
From the completion routine, send the original IRP for processing…
Right?

Yes.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Thanks Maxim!
Just trying to give it a guess, which is the wildest thing to do…Can i do
this to port your IRP replacement solution to the Filter manager’s
framework?

May be its a stupid idea or a question, but i was wondering that can we
actually replace the Callbackdata that we get in the precallback routine
with our own callbackdata.
We all know that we can change parameters like MdlAddress, UserBuffer, etc.
in the Callbackdata. I was just wondering that can we take this modification
to the extent that we actually change ALL the parameters of the callbackdata
OR change the callback data pointed by the “Data” parameter of the
preoperation callback funtion and make it to point to our own callback data.

-K. Dev.

This is not a good idea. Completions of async IRPs can occur at DPC. So sending new IRPs down in the completion path down FS stacks is not tolerated by other filters or the FS.

‘Escaping’ the filter manager framework will not buy you much, if you really wanted to do it that way you can allocate callback data and do exactly the same thing. It still is not correct, and you are still blocking the paging i/o when you wait for it to complete. Freeing the original IRP is a bad idea as well, because you don’t own it.

What I’d like to know is first what you want to exactly do here: if you want to issue a new i/o in the paging path, the new i/o can generate new paging i/o’s unless you are precisely sure that it doesn’t : which is exactly why a deadlock can occur. If you are merely translating the paging i/o however, it’s completely fine, essentially you are substituting the original paging i/o for your own - i.e. you are redirecting? In that case, you would exactly replicate what the original i/o was, if it was synchronous (i.e. it’s a paging i/o read), this is a synchronous paging i/o read as well, if it is asynchronous paging write, this is an asynchronous paging i/o write as well. In general, playing tricks with the i/o system usually doesn’t pay off, it’s really important to understand exactly what you are doing from a bird’s eye view. So if you can please explain that first, we can give more guidance.

thanks
Ravi


From: xxxxx@lists.osr.com on behalf of Maxim S. Shatskih
Sent: Thu 7/26/2007 7:52 PM
To: Windows File Systems Devs Interest List
Subject: Re:[ntfsd] Re:Re:When to use what: FltPerformSynchronousIo & FltPerformAsynchronousIo?

Is it fine to call FltPerformAsynchronousIo in a pre paging write callback
and then wait for an object using KeWaitForSingleObject.

No. Blocking in paging IO paths is a bad idea.

I personally would try to escape from FltMgr’s framework, use IoAllocateIrp for
my operation, fill this IRP, set the original paging write IRP as the
completion context, and submit my IRP down.

The competion routine would destroy this IRP and then submit the original
paging write IRP (completion context) down.

This is 100% async and weakens the deadlock potential a lot.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com http:</http:>


NTDEV 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@windows.microsoft.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

Re:[ntfsd] Re:Re:When to use what: FltPerformSynchronousIo & FltPerformAsynchronousIo?Ok Ravi…

Now let me reframe my original actual question:
I have to do this when i receive a non cached ( paging i/o ) write in my preoperation callback:

  1. Find out the EOF.
  2. Find out the Valid data length in the Buffer. ( This is so because Paging I/O requests are always page aligned and the Buffer size pointed by the Length parameter = Page size ). So, how do i get the Actual length of data present in that buffer?
  3. If this write is on the last page, log the contents of the buffer in another file ( my log file ). Ensure that write has happened.
  4. Allow the original callback data to process only after steps 1-3.

NOTE: I HAVE TO DO ALL THIS IN MY PREOPERATION CALLBACK ROUTINE. AND AFTER DOING ALL THIS I WANT TO RETURN THE ORIGINAL CALLBACK DATA FOR FURTHER PROCESSING.

Thanks!

-K.Dev.

Thanks, this definitely throws more light on your question.

  1. EOF doesn’t change on paging writes or reads. So you can query EOF at a more appropriate time - post create- and track it thence, monitoring normal extending writes and SetEof.
  2. The length indicated in the i/o is the transfer length.
  3. It is interesting you are capturing writes to the ‘last page’ - at any rate knowing if it’s the ‘last’ page is not hard since you have the EOF. You can now write that out to another file using Flt APIs. But it is advisable that you also have the file open already, and you can issue a write to it, as long as the original i/o is not to the paging file. In so doing though, make sure your code is non-pageable.

The one caveat here is that under memory pressure, the memory manager is actively trying to free up physical pages by writing them out. If you are consuming more memory in that path - i.e. doing allocations, you can have failures. You will have to decide how to deal with this - but it is not an option to fail the original write.

Ravi


From: xxxxx@lists.osr.com on behalf of Kernel Developer
Sent: Sat 7/28/2007 2:08 AM
To: Windows File Systems Devs Interest List
Subject: Re: [ntfsd] When to use what: FltPerformSynchronousIo & FltPerformAsynchronousIo?

Ok Ravi…

Now let me reframe my original actual question:
I have to do this when i receive a non cached ( paging i/o ) write in my preoperation callback:

  1. Find out the EOF.
  2. Find out the Valid data length in the Buffer. ( This is so because Paging I/O requests are always page aligned and the Buffer size pointed by the Length parameter = Page size ). So, how do i get the Actual length of data present in that buffer?
  3. If this write is on the last page, log the contents of the buffer in another file ( my log file ). Ensure that write has happened.
  4. Allow the original callback data to process only after steps 1-3.

NOTE: I HAVE TO DO ALL THIS IN MY PREOPERATION CALLBACK ROUTINE. AND AFTER DOING ALL THIS I WANT TO RETURN THE ORIGINAL CALLBACK DATA FOR FURTHER PROCESSING.

Thanks!

-K.Dev.


NTDEV 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: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com

>>It is interesting you are capturing writes to the ‘last page’ - at any

>rate knowing if it’s the ‘last’ page is not hard since you have the EOF.
>You can now write that out to another file using Flt APIs. But it is
>advisable that you also have the file open already, and you can issue a
>write to it, as long as the original i/o is not to the paging file. In so
>doing though, make sure your code is non-pageable.<<

I even want to write in paging i/o path. That is, even if a paging write
comes to a file, I have to write the contents of the buffer to my LOG FILE
(which I have opened in NON CACHED MODE in DriverEntry). So, in this case I
cannot use APIs like FltWriteFile, because they can only be called at
PASSIVE_LEVEL.
But can I call FltAllocateCallbackData and then FltPerformAsynchronousIo and
then wait on an even which I set from the completion routine.
Something of this sort:

PreWriteCallback() {

// i get a paging i/o write

FltAllocateCallbackdata()
FltPerformAsynchronousIo(…,CallbackRoutine,…)
KeWaitForSingleObject(event,INFINITE TIME);
}

Callback(){
KeSetEvent(event);
}

Many people have replied saying that it can lead to deadlock. In that
context, I would like to know the following things:

  1. Will deadlock occur even if I issue a write request to my Log file which
    is open in non cached mode?
  2. Why does the deadlock occur anyways, in the paging i/o path?

Thanks!
K. Dev.