CcCopyRead never returns!

Hi everyone…

I’m (finally) trying to implement cache support in my FSD.

In read, I issue a CcCopyRead with “wait” set to either true or false, and
in either case, CcCopyRead never returns… I determine if this irp can
wait by doing this:

if (IoIsOperationSynchronous(Irp) && (!isset( Irp->Flags, IRP_PAGING_IO
))) then it can wait. (Is this correct?)

I’ve acquired the Fcb Header PagingIoResource Shared.

Since Irp->Flags IRP_NOCACHE is NOT on, I do a CcInitializeCacheMap (if
FileObject->PrivateCacheMap eq NULL).

Then I check if PIO_STACK_LOCATION->MinorFunction is IRP_MN_MDL, (which it
is not), so I do the CcCopyRead.

I’m on W2K Server SP2.

Does anyone have any ideas why this is happening?

Thanks ahead of time,

Greg

Hi Greg,
When you do a CcCopyRead you should be getting a
recursive call to your FSD - only this time, it will
be a non-buffered, pagingIO call. Is this happening?
Is your FSD handling this call properly? Is this call
succeeding?

Manoj

— Greg Pearce wrote: > Hi
everyone…
>
> I’m (finally) trying to implement cache support in
> my FSD.
>
> In read, I issue a CcCopyRead with “wait” set to
> either true or false, and
> in either case, CcCopyRead never returns… I
> determine if this irp can
> wait by doing this:
>
> if (IoIsOperationSynchronous(Irp) && (!isset(
> Irp->Flags, IRP_PAGING_IO
> ))) then it can wait. (Is this correct?)
>
> I’ve acquired the Fcb Header PagingIoResource
> Shared.
>
> Since Irp->Flags IRP_NOCACHE is NOT on, I do a
> CcInitializeCacheMap (if
> FileObject->PrivateCacheMap eq NULL).
>
> Then I check if PIO_STACK_LOCATION->MinorFunction is
> IRP_MN_MDL, (which it
> is not), so I do the CcCopyRead.
>
> I’m on W2K Server SP2.
>
> Does anyone have any ideas why this is happening?
>
> Thanks ahead of time,
>
> Greg
>
>
>
> —
> You are currently subscribed to ntfsd as:
> xxxxx@yahoo.com
> To unsubscribe send a blank email to %%email.unsub%%

=====
-----------------------------------
Manoj Paul Joseph,
Master of Computer Applications (final year student),
School of Computer Science and Engineering,
Anna University,
Chennai (Madras),
India.

________________________________________________________________________
For live cricket scores download Yahoo! Score Tracker
at: http://in.sports.yahoo.com/cricket/tracker.html

Thanks for the reply, Paul.

I’m not sure what I’m seeing… I do see the recursive call I think, but I
must not be handling it correctly. It looks like it blows up with Access
Violation in NtReadFile, and never re-enters my driver.

I have a tester program that does a write then a read. If I don’t do the
write, the read does happen (CcCopyRead actually does finish, and it
returns control to the thread that was executing it), but then the system
fails with access violation in NtReadFile (which I suspect is the
recursive call). I modeled my cache support on the fast fat example, but
I must be missing something somewhere. I’m going to try to fix write
today and maybe that will enlighten me to whatever it is I’m doing wrong
for cache in general.

Thanks again for your help; any further thoughts are greatly appreciated!

Greg

Hi Greg,
If it is a recursive read call, you’ll see the
CcCopyRead in your call stack. Do you see it?
Does the work if you do just the read alone?
Regards,
Manoj

— Greg Pearce wrote: > Thanks for
the reply, Paul.
>
> I’m not sure what I’m seeing… I do see the
> recursive call I think, but I
> must not be handling it correctly. It looks like it
> blows up with Access
> Violation in NtReadFile, and never re-enters my
> driver.
>
> I have a tester program that does a write then a
> read. If I don’t do the
> write, the read does happen (CcCopyRead actually
> does finish, and it
> returns control to the thread that was executing
> it), but then the system
> fails with access violation in NtReadFile (which I
> suspect is the
> recursive call). I modeled my cache support on the
> fast fat example, but
> I must be missing something somewhere. I’m going to
> try to fix write
> today and maybe that will enlighten me to whatever
> it is I’m doing wrong
> for cache in general.
>
> Thanks again for your help; any further thoughts are
> greatly appreciated!
>
> Greg
>
> —
> You are currently subscribed to ntfsd as:
> xxxxx@yahoo.com
> To unsubscribe send a blank email to
%%email.unsub%%

=====
-----------------------------------
Manoj Paul Joseph,
Master of Computer Applications (final year student),
School of Computer Science and Engineering,
Anna University,
Chennai (Madras),
India.

________________________________________________________________________
For live cricket scores download Yahoo! Score Tracker
at: http://in.sports.yahoo.com/cricket/tracker.html

Hello again Manoj,

I see what’s going on but I don’t know what to do about it. A Non-cached
read works fine. But when I do the CcCopyRead call, the read entry point
is entered recursively with a synchrounous paginig IO type of read, gets
the data to satisfy the CcCopyRead request, (the data is in the buffer
ok), and on the way out of the read routine, NtReadFile is the last
recognizable thing in the stack when it blows up on C0000005 AV. The last
thing in the stack (immediatly after NtReadFile) is apparently a call to
address zero. The stack doesn’t look right to me… I think I’m smashing
something somewhere.

Unfortunatly I’m home right now and cannot get the details of this error,
but tomorrow (Thursday) I’ll get stack info and post it in this message
thread if you (or someone else) could look at it and maybe give a clue.

I’m wondering if this is the the way it works:

A read is performed on a file that has cacheing specified. The first Irp
comes into my routine, I MmGetSystemAdressForMdlSafe on the
Irp->MdlAddress, then executes the CcCopyRead call.

This generates another read Irp, which enters the read routine in my FSD
recursively. This time through, this read is synchronous paging I/O, and
causes my FSD to get the file data requested from a user-mode application,
by generating my own ioctl. This causes the 2nd read (from cc) to
complete with “STATUS_PENDING”, until the user mode app ioctl returns with
the data in the buffer. I then complete this Irp with status_success
after filling in the Iosb.Information field with the length read.

Next, cc (I guess) copies the data from the 2nd irp buffer into the first
irp buffer (or to memory)?, and then my original thread gets control out
of the CcCopyRead call, and completes the original Irp with
status_success, and also sets Iosb.Information to the number of bytes
read. When the routine returns to the OS, it bug checks right after
NtReadFile on a C000005.

I hope you guys aren’t laughing too hard…!

Please let me know if this is even remotely close to how it works.

Thanks ahead of time…

Greg

Hi Greg,
So CcCopyRead succeeds now. What you are doing
seems to be fine to me.

  1. Are you calling MmGetSystemAddressForMdl on a valid
    MDL?

if (PtrIrp->MdlAddress)
{
ReturnedBuffer =
MmGetSystemAddressForMdl(PtrIrp->MdlAddress);
}
else
{
ReturnedBuffer = PtrIrp->UserBuffer;
}

If Status is the Status block you pass to
CcCopyRead, check the Status.IoStatus.Status is indeed
STATUS_SUCCESS when CcCopyRead returns and
Status.IoStatus.Information contains the required no
of bytes.
I am not able to think of any other reason why your
driver is causing the crash.
Regards,
Manoj

=====

Manoj Paul Joseph,
Master of Computer Applications (final year student),
School of Computer Science and Engineering,
Anna University,
Chennai (Madras),
India.


For live cricket scores download Yahoo! Score Tracker
at: http://in.sports.yahoo.com/cricket/tracker.html

Thanks for looking at this logic Manoj - I have made some progress since
last night. It looks like the first read my test program issues WORKS,
but it’s actually bombing on the second read in my test program. These
two reads are done against the same open file handle. The second read
attempts to read 40 bytes form beginning of file, which should be
satisfied by cache manager. I don’t see any read irps for this request.
But in the background, there is some other stuff going on apparently,
according to the following stack trace. It appears now that MiCopyOnWrite
is running, which makes no sense to me, because I am reading, not writing.

Please take a look at this:

kd> !analyze -v
*******************************************************************************

*
*
* Bugcheck Analysis
*
*
*
*******************************************************************************

Unknown bugcheck code (0)
Unknown bugcheck description
Arguments:
Arg1: 00000000
Arg2: 00000000
Arg3: 00000000
Arg4: 00000000

Debugging Details:

DEFAULT_BUCKET_ID: DRIVER_FAULT

BUGCHECK_STR: 0

LAST_CONTROL_TRANSFER: from 8049e893 to 00000000

STACK_TEXT:
bcabcc60 8049e893 817539e8 bcabccfc 0000000a 0x0
bcabcd38 804649a1 00000064 00000000 00000000 nt!MiCopyOnWrite+0x165
bcabcd64 80455118 00000000 bcf08d84 bd400c25 nt!MmFlushSection+0x381
bcf08d70 bd400c25 00000000 00000000 00000010
nt!MmLockPagableSectionByHandle+0x59e
bcf08d84 00000000 00000000 00000000 00000000
srv!DereferenceRfcbInternal+0x10f

FOLLOWUP_IP:
srv!DereferenceRfcbInternal+10f
bd400c25 5e pop esi

FOLLOWUP_NAME: MachineOwner

SYMBOL_NAME: srv!DereferenceRfcbInternal+10f

MODULE_NAME: srv

IMAGE_NAME: srv.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 3a636bac

STACK_COMMAND: kb

BUCKET_ID: 0x0_srv!DereferenceRfcbInternal+10f

Followup: MachineOwner

kd>

Thanks again for your help. It is greatly appreciated.

Greg

Manoj,

I’m sorry, I forgot to answer your previous question. I do something
similar to what you have described to obtain the user buffer pointer. My
logic uses MmGetSystemAddressForMdlSafe, at normal page priority. It
always seems to have an MdlAddress, and never has a UserBuffer address on
read, unless a filter driver is above me, like DFS or FileMon.

When FileMon or DFS is running, I do the following, because the MDL
address is null and the Irp->UserBuffer address is the one I need, I
think:

Mdl = IoAllocateMdl (Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
if (Mdl != NULL) {
try {
MmProbeAndLockPages( Mdl, Irp->RequestorMode, IoWriteAccess );
Iosb.Status = STATUS_SUCCESS;
}
except(EXCEPTION_EXECUTE_HANDLER) {
Iosb.Status = GetExceptionCode();
if (!FsRtlIsNtstatusExpected( Iosb.Status ))
{
Iosb.Status = STATUS_INVALID_USER_BUFFER;
}
IoFreeMdl( Mdl );
Irp->MdlAddress = NULL;
}
}

Again, I do this only if (( Irp->MdlAddress == NULL ) && (
Irp->RequestorMode neq KernelMode )) Then I stuff the new Mdl address into
the Irp->MdlAddress and MapUserBuffer on it
(MmGetSystemAddressForMdlSafe). This seems to allow me to work with
FileMon and DFS. This Read problem and other caching problems go away
when file mon runs! This implies to me that I need to MmProbeAndLockPages
in Read, but I don’t see this in FastFat or Nagar’s book, so I dont always
do it.

I use direct_io in my driver, so I looked in the CDFS example for the
above code, and modified it for my use. I don’t know if this is right,
but it does work.

Thanks - Greg

> ok), and on the way out of the read routine, NtReadFile is the last

recognizable thing in the stack when it blows up on C0000005 AV.

Use .cxr command to catch this bugcheck. It will set the stack and “r” command context to the address of where exception occured,
not to the stack of KeBugCheckEx.

Max

At risk of re-demonstrating my ignorance, how do I tell which context
failed, for the .cxr command?

One of the parameter for KMODE_EXCEPTION_NOT_HANDLED bugcheck is the context record.
See !analyze for details.

Max

----- Original Message -----
From: “Greg Pearce”
To: “File Systems Developers”
Sent: Thursday, May 09, 2002 9:04 PM
Subject: [ntfsd] Re: CcCopyRead never returns!

> At risk of re-demonstrating my ignorance, how do I tell which context
> failed, for the .cxr command?
>
> —
> You are currently subscribed to ntfsd as: xxxxx@storagecraft.com
> To unsubscribe send a blank email to %%email.unsub%%
>

Max -

The analyze shows all args = 00000000. I pasted the output from this
command in a post 5 messages up in this message thread. It’s bugcheck 0
too, it looks like.

I read somewhere that context is parameter 2, I think, but all args being
zeros confused me…

Thanks - Greg