Yes you are doing more than is necessary, you can treat all IRPs the
same.
There is not issue with delaying the return of an Asynchronous IO. All
it will do is degrade the IO throughput of the application doing the
asynch IO because it may not be able to queue up multiple concurrent
IO’s.
Neal Christiansen
Microsoft File System Filter Group Lead
This posting is provided “AS IS” with no warranties, and confers no
rights
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Don
Sent: Friday, October 08, 2004 7:10 AM
To: Windows File Systems Devs Interest List
Subject: Re:[ntfsd] Filter Driver Thread Context question.
Tony,
Thanks much. This is pretty much what I have changed things to. I am now
simply waiting in the Filter Drivers Read and Write function until it is
OK
for that I/O to proceed. Then I hand down the IRP to the FSD, still in
the
original context… This avoids all the locking problems.
The one concern that I still have is that sometimes the IRPs are marked
as
Asynchronous (according to IoIsOperationSynchronous). It is my
understanding
that BAD things happen if you block a thread when the operation is not
synchronous.
So I currently have a model where if the IRP is Synchronous, I simply
hold
onto it for a while (by waiting for an event), and then send it down to
the
FSD. If it is not Synchronous, I am putting it in my IRP queue and
sending
it to the FSD in the worker thread. This seems to be avoiding the
deadlocks
(I started seeing them all the time as soon as I tried to access the
disk
over the network).
Am I doing more than is necessary here? Would it actually be OK to treat
all
IRPs the same, and just hold onto them until it is their time, even if
they
are not Synchronous?
Thanks,
Don
“Tony Mason” wrote in message news:xxxxx@ntfsd…
Don,
The one thing to keep in mind with locking is that we are talking about
per-file serialization here. The deadlock potential that arises is
between I/O operations against the same file, which might explain why
you aren’t seeing this yet.
If you wish to rate-limit the flow of I/O operations into the file
system, just do it directly. Don’t use worker threads to defer the
operations (and most assuredly DO NOT use system work queues under any
circumstances or you will see a worker thread deadlock at some point).
Build a simple priority queue, and rate-limit low priority operations
when there are high priority operations pending. I’ve seen this done
successfully before and I do not recall that it required a complicated
implementation model.
Regards,
Tony
Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Don
Sent: Thursday, October 07, 2004 6:03 PM
To: ntfsd redirect
Subject: Re:[ntfsd] Filter Driver Thread Context question.
Tony and Alexei,
Your concerns about locking have me wondering if I am taking the wrong
approach to solving my problem. The objective is to slow down most I/O
that
actually hits the disk. We have certain open files that MUST have
guaranteed
high performance access to the storage device. The problem is that some
user
can come along with the explorer or the network server and copy one file
to
another, causing the important file to not be able to access the disk
well
enough.
The point of this filter is to sort of meter all of the unimportant I/O
(which to us, is everything but a few selected handles). Thus the
filters
worker thread issues an I/O, waits for a period of time based on the
size of
the I/O, and then issues another one. While the important I/O bypasses
this
entirely and goes straight to the file system. I am also blocking the
fast
I/O path for all unimportant I/O, just to keep things simpler in the
filter.
I considered another approach where I would make the “unimportant” I/Os
wait
for an event until it was time to send them down to the disk system.
Thus,
they would be called in their original context, but they would have to
wait
a while. However, I thought that by doing this I would break the
asynchronous I/O calls. I wanted a user app that was doing async I/O to
get
an immediate return, not to wait until my metering thread decides to let
it’s I/O proceed. Hence I was pending the I/Os and sending them down in
my
worker thread.
How much trouble am I getting myself into here? It doesn’t seem that
there
is any way for a filter driver to hook the AcquireForLazyWriter stuff.
Thanks for your help,
Don
“Tony Mason” wrote in message news:xxxxx@ntfsd…
Don,
(1) Context = “virtual address space” and “object handle table” and
“security credentials”. If you want to interpret user addresses
correctly, do it using the right virtual address space.
(2) That shouldn’t be necessary. There’s no ordering requirement on
queuing versus formatting for the call down. If you look at
IoCopyCurrentIrpStackLocationToNext, notice that it clears out the
Control field (where the SL_PENDING_RETURNED bit is set).
The basic algorithm you described is reasonable. The one other point
that Alexei made (and an excellent point) is that you need to be
cognizant of the locking that is done in these code paths as well. File
systems DO post these requests, but are also keenly aware of the locking
considerations here.
I hope this helps.
Regards,
Tony
Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com
Looking forward to seeing you at the Next OSR File Systems Class October
18, 2004 in Silicon Valley!
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Don
Sent: Thursday, October 07, 2004 12:45 PM
To: ntfsd redirect
Subject: Re:[ntfsd] Filter Driver Thread Context question.
Tony,
Thanks for you response. You have clarified a lot for me.
I used the cancel safe queue because it seemed quick and easy and like
it
would do the right thing. You are right that I don’t really care that
much
about the ability to cancel.
However, your answer has brought up two questions that I hope you can
help
me with.
1. You said “Provided that you are properly locking down the user
buffer…” Does this mean that I need to lock down the user buffer
before I
queue the IRP for the thread to handle later. I assumed the the File
System
would lock down the user buffer, but perhaps it can’t do that without
being
in the right context. Could you elaborate just a bit more on that.
2. Just for clarification, I need to copy the stack location to next
BEFORE I mark the irp pending. Is that correct?
So it sounds like the proper thing to do in my IRP_MJ_READ or
IRP_MJ_WRITE
handeler is:
if (this is the kind of read or write I care about)
{
Lock Down user buffers.
CopyIrpStackLocationToNext;
SetIrpPending
Put the IRP in my queue
return STATUS_PENDING.
}
else
{
IoSkipCurrentIrpLocation
return CallDriver
}
Then, in the thread
{
while (forever)
{
Wait for an IRP in the queue
Get the IRP from the queue.
CallDriver (and ignore the return value)
}
}
Does this seem correct to you?
Thanks,
Don
“Tony Mason” wrote in message news:xxxxx@ntfsd…
Context is not the issue here, assuming you are properly locking down
the user buffer for those IRPs arriving from user applications
(non-cached but not paging - all paging are automatically non-cached).
Both NTFS and FAT already have to deal with this case anyway (since they
can post I/O operations and then process them in a separate thread
context in the “background”)
However, once you mark the I/O Stack location as pending, you can’t then
skip the I/O stack location - at some point that is going to bite you
because you have now set the pending bit in your nonexistent stack
location. This WORKS for paging I/O because of the unique way that
paging I/O is completed (with all APCs disabled, so an event is set
rather than an APC being enqueued) but won’t work when you see
non-cached user I/O - you’ll end up seeing bugcheck 0x44 periodically
(not EVERY time because it will depend upon timing and the specifics of
the I/O operation).
The safe way to do this is IoCopyCurrentIrpStackLocationToNext. Then
you can set the bit in your own I/O stack location all you want.
Unrelated to your actual question, there’s really no reason to use
cancel safe queues in this case anyway - I certainly wouldn’t bother
supporting I/O cancellation in my file system drivers for read/write I/O
operations. Easier just to finish the I/O than to burden this path with
so much annoying complexity. If you look, you will notice that FAT
doesn’t support cancel routines. Any cancelable operations are outside
FAT in the FsRtl operations (e.g., directory change notification and
oplock management). Redirectors can support cancellation because they
have high-latency paths, but even that is unusual.
Regards,
Tony
Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com
Looking forward to seeing you at the Next OSR File Systems Class October
18, 2004 in Silicon Valley!
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Don
Sent: Thursday, October 07, 2004 10:16 AM
To: ntfsd redirect
Subject: [ntfsd] Filter Driver Thread Context question.
Hi all,
I am developing a FS filter driver that is primarily intended to sit on
top
of NTFS. In this filter, almost all IRPs are passed on to the underlying
file system by using the following code:
IoSkipCurrentIrpStackLocation (irp);
return (IoCallDriver (devExt->AttachedToDeviceObject, irp));
However, some IRPs go through a different path. Specifically, these are
read
and write IRPs that meet the following criteria:
The target file must not be a directory, a volume, a device, or a paging
file. Furthermore, the I/O must be either pagingIo or nonCachedIo.
These IRPs are placed in a Cancel-Safe IRP Queue using IoCsqInsertIrp,
which
automatically marks the IRP pending. I then return STATUS_PENDING.
The filter driver has it’s own thread which pulls these IRPs off of the
queue using IoCsqRemoveNextIrp, and then does the following:
IoSkipCurrentIrpStackLocation (irp);
IoCallDriver (devExt->AttachedToDeviceObject, irp);
Thus, the IRP is eventually passed onto the FSD unmodified (other than
having been marked pending), but the FSD ends up getting called in the
context of my thread instead of the original calling context.
This seems to work, but I have this nagging worry that I am doing
something
bad here. Is it really OK to change the context that the IRP is
delivered to
the FSD in like this? If not, is there some way to get back in the
original
context before I call IoCallDriver?
Thanks in advance for any input.
Don
—
Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17
You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to xxxxx@lists.osr.com
—
Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17
You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to xxxxx@lists.osr.com
—
Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17
You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to xxxxx@lists.osr.com
—
Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17
You are currently subscribed to ntfsd as: xxxxx@windows.microsoft.com
To unsubscribe send a blank email to xxxxx@lists.osr.com