I have a top level driver that is using NEITHER I/O most of
the time; however, I do have a couple of cases where I can’t
process the I/O immediately, so I want to call IoAllocateMdl.
My question is two-fold:
- Can I tack the MDL onto the IRP I’m processing?
I.e.,
NTSTATUS MyReadDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
IoAllocateMdl(Irp->UserBuffer,
IoStack->Parameters.Read.Length,
FALSE,
TRUE,
Irp);
IoCsqInsertIrp(&pDeviceExtension->csq, Irp, 0);
IoMarkIrpPending(Irp);
return STATUS_PENDING;
}
- If so, will the IO Manager clean it up for me, or do I
need to clean it up myself before completing the I/O.
Thanks,
Joseph
Joseph,
I have a top level driver that is using NEITHER I/O most of
the time; however, I do have a couple of cases where I can’t
process the I/O immediately, so I want to call IoAllocateMdl.
My question is two-fold:
- Can I tack the MDL onto the IRP I’m processing?
I.e.,
NTSTATUS MyReadDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
IoAllocateMdl(Irp->UserBuffer,
IoStack->Parameters.Read.Length,
FALSE,
TRUE,
Irp);
IoCsqInsertIrp(&pDeviceExtension->csq, Irp, 0);
IoMarkIrpPending(Irp);
return STATUS_PENDING;
}
AFAIK you can do this.
But then you will have to map the MDL to system address space to access it from another thread context.
Also I would change your sample code as follows to prevent races when the IRP is cancelled before it is marked as pending.
{
pMdl = IoAllocateMdl(Irp->UserBuffer,
IoStack->Parameters.Read.Length,
FALSE,
TRUE,
Irp);
if( !pMdl ) // do something to handle the low resources condition
IoMarkIrpPending(Irp); // do this before inserting into the CSQ
IoCsqInsertIrp(&pDeviceExtension->csq, Irp, 0);
return STATUS_PENDING;
}
- If so, will the IO Manager clean it up for me, or do I
need to clean it up myself before completing the I/O.
I’ve never used such a techniq in myself but i guess it should work.
The other way (in the case when you passing the IRP down the stack) is to set your own Completion routine and free the MDL in it.
And don’t forget to set Irp->MdlAddress = NULL after that.
Best regards,
Valeriy Glushkov
Thanks,
Joseph
Valeriy Glushkov wrote:
>I have a top level driver that is using NEITHER I/O most of
>the time; however, I do have a couple of cases where I can’t
>process the I/O immediately, so I want to call IoAllocateMdl.
>
>My question is two-fold:
>
>+ Can I tack the MDL onto the IRP I’m processing?
>
> I.e.,
>
> NTSTATUS MyReadDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
> {
> IoAllocateMdl(Irp->UserBuffer,
> IoStack->Parameters.Read.Length,
> FALSE,
> TRUE,
> Irp);
>
> IoCsqInsertIrp(&pDeviceExtension->csq, Irp, 0);
> IoMarkIrpPending(Irp);
> return STATUS_PENDING;
> }
AFAIK you can do this.
Great… it seems to be working, but that isn’t
always a definitive answer 
But then you will have to map the MDL to system address space to access it
> from another thread context.
>
Also I would change your sample code as follows to prevent races when
> the IRP is cancelled before it is marked as pending.
{
pMdl = IoAllocateMdl(Irp->UserBuffer,
IoStack->Parameters.Read.Length,
FALSE,
TRUE,
Irp);
if( !pMdl ) // do something to handle the low resources condition
IoMarkIrpPending(Irp); // do this before inserting into the CSQ
IoCsqInsertIrp(&pDeviceExtension->csq, Irp, 0);
return STATUS_PENDING;
}
Thanks for the hint. That makes perfect sense.
I also had to call MmProbeAndLockPages() on the MDL as well,
which I did here-- I think the I/O manager calls MmProbeAndLockPages()
for the buffer when it creates an IRP for a direct I/O request. Can
anyone confirm this?
>+ If so, will the IO Manager clean it up for me, or do I
> need to clean it up myself before completing the I/O.
I’ve never used such a techniq in myself but i guess it should work.
The other way (in the case when you passing the IRP down the stack) is to set your own Completion routine and free the MDL in it.
And don’t forget to set Irp->MdlAddress = NULL after that.
All right. Maybe I’ll see if I can’t stress things a little
bit and see what happens. if the MDLs aren’t being cleaned up
it should become obvious pretty quick…
Thanks for you help,
Joseph
On Mon, 2004-07-05 at 18:05, Valeriy Glushkov wrote:
Also I would change your sample code as follows to prevent races when the IRP is cancelled before it is marked as pending.
{
pMdl = IoAllocateMdl(Irp->UserBuffer,
IoStack->Parameters.Read.Length,
FALSE,
TRUE,
Irp);
if( !pMdl ) // do something to handle the low resources condition
IoMarkIrpPending(Irp); // do this before inserting into the CSQ
IoCsqInsertIrp(&pDeviceExtension->csq, Irp, 0);
return STATUS_PENDING;
}
CSQ will mark the IRP pending.
-sd
You had several questions:
(a) Can I “tack the MDL onto the IRP” as shown
This was answered. Yes, you can. Though I’d personally allocate the
MDL, probe and lock the pages (see below) and then stick a pointer to
the MDL into Irp->MdlAddress manually – At least this makes is clear in
your code that you’re doing this and not relying on a seldom-used
parameter in IoAllocateMdl. AND you can comment it separately.
(b) If I do this, and I leave the MDL in the IRP, will the I/O Manager
“unlock the pages” and de-allocate the IRP for me.
Answer: Yes. I’ve done it many, many, times.
(c) Does the I/O Mgr probe and lock the pages of the user’s data buffer
when you use Neither I/O?
Answer: Absolutely not. The user’s pages that contain the data buffer
are pageable – assuming they weren’t already locked for some other
reason – when you’re called with neither I/O.
And now for an editorial: Do you really, really, need to use neither I/O
in your driver? I just HATE to see people use neither I/O unless (a)
they absolutely have no alternative, AND (b) they’re totally committed
to testing their code in a very comprehensive manner.
Otherwise, using neither I/O is just another way of asking for trouble.
Peter
OSR
PeterGV wrote:
You had several questions:
> […]
Thanks-- that is good information, and answers
my questions definitively.
And now for an editorial: Do you really, really, need to use neither I/O
in your driver? I just HATE to see people use neither I/O unless (a)
they absolutely have no alternative, AND (b) they’re totally committed
to testing their code in a very comprehensive manner.
I’m actually writing a filesystem redirector, so I think I
fall in the have no (reasonable) choice category. Right
now, it is a proof of principle (POP). As I learn more about
it, I might decide that one of the unreasonable choices
is reasonable.
Since the network protocol requires encryption and several
layers, and we already have a working, well debugged
userland implementation, I’m bouncing the data back down
to usermode for the network. (That way I can focus on
learning one big hairy thing at a time 
So when I handle IRP_MJ_READ / IRP_MJ_WRITE from my
userland protocol implementation, I need to process
them asynchronously-- which means changing the
Neither I/O into Direct I/O…
So, while I have everyones attention, is it reasonable
to drive the networking through usermode for a POP?
How about for production code?
Otherwise, using neither I/O is just another way of asking for trouble.
Thanks for the help and the warning. I hope I’ll
be okay if I just remember I either have to process
the I/O completely in dispatch or ‘convert’ it to
a Direct I/O.
Thanks,
“Joseph Galbraith” wrote in message news:xxxxx@ntdev…
>
> So, while I have everyones attention, is it reasonable
> to drive the networking through usermode for a POP?
>
Absolutely.
The only real issue that you’ll need to be aware of is the potential for
deadlocks as a result of pumping requests back to usermode. I’m not saying
it can’t be done, or that you will definitely have problems, just that if
you run into things that look strange (“the user app hangs when I’m in the
debugger, but not when I run it outside the debugger” for example) you’ll
want to carefully consider the potential of a deadlock.
> How about for production code?
>
Well, I guess it all depends on the volume of data and the required
throughput, right? Almost every solution is appropriate in SOME situation.
There are certainly a variety of products that work by passing their data
back to usermode. There seems to be a preference among many developers for
developing/debugging in user mode. Personally, I’ve never understood it,
but kernel-mode is the only place I ever write code. Funelling operations
back to user mode is quite commonly done. All-in-all, the cost of ring
transitions these days tends to be over-stated.
Given that you’re doing a network file system, you might find additional
file-system specific help on the NTFSD list. And I don’t scold people about
using method neither over there 
Peter
OSR
On Tue, 2004-07-06 at 22:13, Peter Viscarola wrote:
“Joseph Galbraith” wrote in message news:xxxxx@ntdev…
> >
> > So, while I have everyones attention, is it reasonable
> > to drive the networking through usermode for a POP?
> Absolutely.
>
> The only real issue that you’ll need to be aware of is the potential for
> deadlocks as a result of pumping requests back to usermode.
I have a driver that does this, in fact. I spent some time talking with
Microsoft folks about this architecture at the last DevCon, and (for my
particular architecture, at least) we arrived at the opinion that it
shouldn’t cause any locks. Everyone I asked started with the former
opinion, though, and it took some consideration to end up where we did.
One person recommended that I avoid all usermode libraries other than
ntdll for the reentrant calls back to the kernel (due to nonspecific
deadlock concerns), but empirical evidence has born out the architecture
so far.
I’d be interested in hearing more about your architecture, as well as
any problems you might run into.
Now, that said, this most certainly does NOT work on 9x. It looks like
it does, for a while, but there are fairly major reentrancy bugs that
prevent this stuff from working right.
> > How about for production code?
> >
> Well, I guess it all depends on the volume of data and the required
> throughput, right? Almost every solution is appropriate in SOME situation.
> There are certainly a variety of products that work by passing their data
> back to usermode.
Yeah, I concur with that. We’ve measured it, and it depends on your
architecture, but k/u switches aren’t too expensive. Keep an eye on
context switches, though, which are worse. When in doubt, profile.
The whole question is one of finding the bottlenecks. If you’re talking
about networking, and your typical use of your driver is on a cable
modem or 802.11b network, k/u is probably not the limiting factor.
Profiling and perf testing are the only ways to know, though.
> There seems to be a preference among many developers for
> developing/debugging in user mode. Personally, I’ve never understood it,
> but kernel-mode is the only place I ever write code. Funelling operations
> back to user mode is quite commonly done.
There are some kinds of tasks that devs do in kernel mode that seem to
be perfectly doable in user-mode, and in that case, my preference is
always for writing the least-privileged code possible. Until Alberto’s
utopia of ring-1 filesystem drivers (was that it?) happens, you really
only have two choices for priv level. Furthermore, there is a large
body of existing code (c++ crypto code, for example) that exists for
usermode but is a pain to port to kernel mode. For the crypto example,
the encryption process probably dwarfs the ring transition time, which
works out nicely.
One of the MS folks told me that he was interested in what other things
could be accomplished from less-privileged code as well. It just makes
sense to me, from a security standpoint, to move in that direction.
-sd