File Mapping

Hi,

I’m writing a filter driver for backup/restore purposes. Files that have been backuped are marked with a ReparsePoint. What I need to do is, when I get a R/W request to hold the IRP until I rewrite such file with original content (restore). This works pretty well for most cases except File Mapping. In this case the FileObject receives a Cleanup IRP after IRP_MJ_CREATE and I’m unable to issue a write IRP to such an object. How to get around this w/o opening the file again?

Thanks,
Martin

> In this case the FileObject receives a Cleanup IRP after IRP_MJ_CREATE and

I’m unable to issue a write IRP to such an object. How to get around this
w/o opening the file again?

You should issue a paging R/W request, but be careful - paging requests are
processed and completed in a special way.


Slava Imameyev, xxxxx@hotmail.com

wrote in message news:xxxxx@ntfsd…
> Hi,
>
> I’m writing a filter driver for backup/restore purposes. Files that have
> been backuped are marked with a ReparsePoint. What I need to do is, when I
> get a R/W request to hold the IRP until I rewrite such file with original
> content (restore). This works pretty well for most cases except File
> Mapping. In this case the FileObject receives a Cleanup IRP after
> IRP_MJ_CREATE and I’m unable to issue a write IRP to such an object. How
> to get around this w/o opening the file again?
>
> Thanks,
> Martin
>

If the app creates a writeable file mapping and closes the handle, then
sorry, CLEANUP is sent, and the app’s writes can follow it.

Tracking CLOSE is your only chance.


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

wrote in message news:xxxxx@ntfsd…
> Hi,
>
> I’m writing a filter driver for backup/restore purposes. Files that have been
backuped are marked with a ReparsePoint. What I need to do is, when I get a R/W
request to hold the IRP until I rewrite such file with original content
(restore). This works pretty well for most cases except File Mapping. In this
case the FileObject receives a Cleanup IRP after IRP_MJ_CREATE and I’m unable
to issue a write IRP to such an object. How to get around this w/o opening the
file again?
>
> Thanks,
> Martin
>

Thx for the responses. I’m tracking the R/W request and in this stage I need to write to the same FileObject. A nice example of problem is the good Notepad (read file mapping). How different are the Paging requests handled?

>How different are the Paging requests handled?

  • Data granularity is a page size ( you should mimic the system behaviour )
  • Mdl is used ( do not forget to lock pages )
  • Irp->UserBuffer is set to MmGetMdlVirtualAddress( Irp->MdlAddress )
  • Mdl is not unmapped and pages are not unlocked when Irp is being
    completed, the Irp creator( i.e. the request initiator ) must unmap, unlock
    and free the MDL
  • Paging requests can’t extend file ( data beyond the end of file is
    discarded )

and do not forget to set IRP_PAGING_IO flag for your Irp


Slava Imameyev, xxxxx@hotmail.com

wrote in message news:xxxxx@ntfsd…
> Thx for the responses. I’m tracking the R/W request and in this stage I
> need to write to the same FileObject. A nice example of problem is the
> good Notepad (read file mapping). How different are the Paging requests
> handled?
>

> - Data granularity is a page size ( you should mimic the system behaviour )

  • Mdl is used ( do not forget to lock pages )

Mm sends this MDL with pages already locked.

Also, I never saw the MDL with unlocked pages crossing the driver’s boundary -
i.e. arriving to dispatch routine as ->MdlAddress.


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

> Mm sends this MDL with pages already locked.

The question was about creating paging request by hand, I made the remark
about locking to warn against the common error.

P.S.
Actually, when Mm( i.e. Memory Manager ) sends paging request it doesn’t
“lock” any pages( i.e. allocates locked page frames for the buffer and fill
them with data) as there is no any virtual buffer associated with the
request - there are only real pages which are always here and which are
either have been modified(in case of write) or doesn’t contain valid data(
in case of read ). So the phrase “Mm sends this MDL with pages already
locked” which in this discussion context should be read as “Mm sends MDL for
paging requests with pages already locked” sounds very strange as Mm can’t
send paging request with an MDL for a virtual buffer as Mm’s MDLs used in
paging requests describe ONLY PAGES not BUFFERS.


Slava Imameyev, xxxxx@hotmail.com

“Maxim S. Shatskih” wrote in message
news:xxxxx@ntfsd…
>> - Data granularity is a page size ( you should mimic the system
>> behaviour )
>> - Mdl is used ( do not forget to lock pages )
>
> Mm sends this MDL with pages already locked.
>
> Also, I never saw the MDL with unlocked pages crossing the driver’s
> boundary -
> i.e. arriving to dispatch routine as ->MdlAddress.
>
> –
> Maxim Shatskih, Windows DDK MVP
> StorageCraft Corporation
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>

> P.S.

Actually, when Mm( i.e. Memory Manager ) sends paging request it doesn’t
“lock” any pages( i.e. allocates locked page frames for the buffer and fill
them with data) as there is no any virtual buffer associated with the
request - there are only real pages which are always here and which are
either have been modified(in case of write) or doesn’t contain valid data(
in case of read ).

Correct, to be exactly, it is so, also, IoAllocateMdl is not used, and the MDL
is a part of a large structure allocated by MiAllocateInPageSupportBlock.

I have reverse engineered this path in around 98-99.

So the phrase “Mm sends this MDL with pages already
locked”

Well, these pages are not subject to working set trimming for sure :slight_smile:


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

Thanks!
That’s actually what I tried some time ago, but it didn’t work and I keep getting STATUS_MULTIPLE_FAULT_VIOLATION from IoCallDriver with such a request…
Any idea why?

Martin

>That’s actually what I tried some time ago, but it didn’t work

Any idea why?

Provide us with the code and we provide you with an idea.


Slava Imameyev, xxxxx@hotmail.com

wrote in message news:xxxxx@ntfsd…
> Thanks!
> That’s actually what I tried some time ago, but it didn’t work and I keep
> getting STATUS_MULTIPLE_FAULT_VIOLATION from IoCallDriver with such a
> request…
> Any idea why?
>
> Martin
>

IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
IoAllocateMdl( pBuffer, writeLength, FALSE, FALSE, FALSE );
MmBuildMdlForNonPagedPool( pMDL );
irp->Flags = IRP_NOCACHE | IRP_WRITE_OPERATION;
if( FileObject->Flags & FO_CLEANUP_COMPLETE )
irp->Flags |= IRP_PAGING_IO;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->RequestorMode = KernelMode;
irp->UserIosb = ioStatus;
irp->UserEvent = NULL;
irp->UserBuffer = pBuffer;
irp->MdlAddress = pMDL;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_WRITE;
irpSp->MinorFunction = IRP_MN_NORMAL;
irpSp->FileObject = FileObject;
irpSp->DeviceObject = NextDeviceObject;
irpSp->Parameters.Write.Length = writeLength;
irpSp->Parameters.Write.ByteOffset.QuadPart = pliFileOffset->QuadPart;
Initialize Completion Event
IoSetCompletionRoutine
IoCallDriver( NextDeviceObject, irp );

Seems the status is probably returned by MiResolveTransitionFault…

// A transition PTE is either on the free or modified list,
// on neither list because of its ReferenceCount
// or currently being read in from the disk (read in progress).
// If the page is read in progress, this is a collided page
// and must be handled accordingly.

if (Pfn1->u3.e1.ReadInProgress) {

CapturedEvent = (PMMINPAGE_SUPPORT)Pfn1->u1.Event;

CurrentThread = PsGetCurrentThread();

if (CapturedEvent->u.Thread == CurrentThread) {

// This detects MmCopyToCachedPage deadlocks where both the
// user and system address point at the same physical page.
//
// It also detects when the Io APC completion routine accesses
// the same user page (ie: during an overlapped I/O) that
// the user thread has already faulted on.
//
// Both cases above can result in fatal deadlocks and so must
// be detected here. Return a unique status code so the
// (legitimate) callers know this has happened so it can be
// handled properly. In the first case above this means
// restarting the entire operation immediately. In the second
// case above it means requesting a callback from the Mm
// once the first fault has completed.
//
// Note that non-legitimate callers must get back a failure
// status so the thread can be terminated.


Maybe because the original Read IRP is still pending?

> That’s actually what I tried some time ago, but it didn’t work and I keep

getting STATUS_MULTIPLE_FAULT_VIOLATION

It seems that your design is totaly faulty. This is a special status code
and it can be processed only by the system, all you can do in this case is
trying to repeat the request, but in any case - this code says - this is a
serious flaw in your design as you somehow generate a write request for the
page in the same thread which already waiting for the pagefault completion.

if( FileObject->Flags & FO_CLEANUP_COMPLETE )

Why do you use the FO_CLEANUP_COMPLETE flag?
How do you synchronize with the complete request? Remembering the problem
with STATUS_MULTIPLE_FAULT_VIOLATION I guess that there is a lack of
syncronization between your code and the system( including FSD ).

IoSetCompletionRoutine

What does the completion routine do?
What do you do if STATUS_PENDING is returned?

irpSp->DeviceObject = NextDeviceObject;

You don’t have to do this, but this is not an error.

P.S. And please stop publishing here the source codes which is not yours and
which is not under any open source license, nobody will discuss this code
here.


Slava Imameyev, xxxxx@hotmail.com

wrote in message news:xxxxx@ntfsd…
> IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
> IoAllocateMdl( pBuffer, writeLength, FALSE, FALSE, FALSE );
> MmBuildMdlForNonPagedPool( pMDL );
> irp->Flags = IRP_NOCACHE | IRP_WRITE_OPERATION;
> if( FileObject->Flags & FO_CLEANUP_COMPLETE )
> irp->Flags |= IRP_PAGING_IO;
> irp->Tail.Overlay.Thread = PsGetCurrentThread();
> irp->RequestorMode = KernelMode;
> irp->UserIosb = ioStatus;
> irp->UserEvent = NULL;
> irp->UserBuffer = pBuffer;
> irp->MdlAddress = pMDL;
> irpSp = IoGetNextIrpStackLocation( irp );
> irpSp->MajorFunction = IRP_MJ_WRITE;
> irpSp->MinorFunction = IRP_MN_NORMAL;
> irpSp->FileObject = FileObject;
> irpSp->DeviceObject = NextDeviceObject;
> irpSp->Parameters.Write.Length = writeLength;
> irpSp->Parameters.Write.ByteOffset.QuadPart = pliFileOffset->QuadPart;
> Initialize Completion Event
> IoSetCompletionRoutine
> IoCallDriver( NextDeviceObject, irp );
>
>

> It seems that your design is totaly faulty. This is a special status code

and it can be processed only by the system, all you can do in this case is
trying to repeat the request, but in any case - this code says - this is a
serious flaw in your design as you somehow generate a write request for the
page in the same thread which already waiting for the pagefault completion.

That’s what I thought - the original Read IRP (issued probably by a pagefault on File Mapping) is still pending within the same thread and this issues a new Write… How to solve this, different thread, satisfy the first pending request ?

Why do you use the FO_CLEANUP_COMPLETE flag?

Because for other situations (not file mapping) I don’t need to use the Paging IO and ti works. I use this to detect if this is a mapping request (the FileObject has already got IRP_MJ_CLEANUP).

What does the completion routine do?

Frees the IRP, sets sync event.

Martin

>How to solve this, different thread, satisfy the first pending request ?

Use any solution. Look at what happened with your current design - there
were two concurrent paging requests for the same page in a thread - the
first is a syncronous read the second is an asynchronous write, such a
behaviour is undeterministic. Revamp the design to make it fully
deterministic.

> What does the completion routine do?

Frees the IRP, sets sync event.

So, you unmap and unlock the Mdl by calling MmUnlockPages. If so then it is
OK.


Slava Imameyev, xxxxx@hotmail.com

wrote in message news:xxxxx@ntfsd…
>> It seems that your design is totaly faulty. This is a special status code
>> and it can be processed only by the system, all you can do in this case
>> is
>> trying to repeat the request, but in any case - this code says - this is
>> a
>> serious flaw in your design as you somehow generate a write request for
>> the
>> page in the same thread which already waiting for the pagefault
>> completion.
>
> That’s what I thought - the original Read IRP (issued probably by a
> pagefault on File Mapping) is still pending within the same thread and
> this issues a new Write… How to solve this, different thread, satisfy the
> first pending request ?
>
>> Why do you use the FO_CLEANUP_COMPLETE flag?
>
> Because for other situations (not file mapping) I don’t need to use the
> Paging IO and ti works. I use this to detect if this is a mapping request
> (the FileObject has already got IRP_MJ_CLEANUP).
>
>> What does the completion routine do?
>
> Frees the IRP, sets sync event.
>
> Martin
>