Shadow copy of file content in FS filter

I whant to make copy of all files written to disk in the special folder. So I
have my own file system filter driver, I create new file for shadow copy each
time when dispatch routine for IRP_MJ_CREATE is called (with appropriate
create options), and write to this file from dispatch routine for
IRP_MJ_WRITE. I use IoCreateFileSpecifyDeviceObjectHint to create file and
ZwWriteFile to write. But call to ZwWriteFile fails with
STATUS_FILE_LOCK_CONFLICT status. Moreover, when I call ZwWriteFile, I often
get same status in calls to low-level drivers (IoCallDriver for
IRP_MJ_WRITE), so system make several attempts to write file before success.
This behavior differs in depending on application which writes the file:
explorer.exe always write data successfully to the main destination and to
shadow copy, Mspaint always hangs, and notepad.exe writes big file after 2 -5
attempts.

My code:

NTSTATUS EskdDispatchForWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PESKD_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT fileObject = pIrpStack->FileObject;
PESKD_FILE_OBJECT eskdFileObject =
GetFileObjectEntryByFileObject(fileObject);
PIO_STACK_LOCATION pNewStack;
IO_STATUS_BLOCK IoStatusBlock;
KEVENT event;
PKEVENT pEvent1;
HANDLE hSadowEvent;
NTSTATUS statusWrite;
NTSTATUS statusCall;
LARGE_INTEGER offset;
ULONG length=0;
void* writeBuffer;

pEvent1=IoCreateSynchronizationEvent(NULL, &hSadowEvent);

if (eskdFileObject && eskdFileObject->cacheFileHandle)
{

PRINT_DEBUG_EX(“Process: %x; %wZ; Buffer length
%i”,PsGetCurrentProcessId(),&eskdFileObject->cacheFileName,
pIrpStack->Parameters.Write.Length);

statusWrite=STATUS_UNSUCCESSFUL;

offset=pIrpStack->Parameters.Write.ByteOffset;
length=pIrpStack->Parameters.Write.Length;

PRINT_DEBUG_EX(“Offset %x”,offset);

IoCopyCurrentIrpStackLocationToNext(Irp);
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)
EskdCompleteIRP, &event, TRUE, TRUE, TRUE);
statusCall = IoCallDriver(devExt->AttachedToDeviceObject, Irp);
PRINT_DEBUG_EX(“IoCallDriver status %x”,statusCall);

if(statusCall==STATUS_PENDING)
{
KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE,
NULL );
}

if(Irp->MdlAddress)
{

writeBuffer=MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);
PRINT_DEBUG(writeBuffer ? “Mdl mapped OK” : “Mdl mapped
NULL”);
}
else
{
writeBuffer=Irp->UserBuffer;
PRINT_DEBUG(writeBuffer ? “UserBuffer OK” : “UserBuffer
NULL”);
}

//!!! This function cause the block
statusWrite=ZwWriteFile(eskdFileObject->cacheFileHandle,
hSadowEvent,
NULL,
NULL,
&IoStatusBlock,
writeBuffer,//Irp->AssociatedIrp.SystemBuffer,
length ,
&offset,
NULL
);

PRINT_DEBUG_EX(“ZwWriteFile status %x”,statusWrite);

if(statusWrite==STATUS_PENDING)
{
KeWaitForSingleObject(pEvent1,
Executive,
KernelMode,
FALSE,
NULL );
}

ZwClose(hSadowEvent);

IoCompleteRequest(Irp, IO_NO_INCREMENT);

return Irp->IoStatus.Status;

}
else
{
return EskdPassThrough(DeviceObject,Irp);
}

}

File handle is opened in dispatch routine for IRP_MJ_CREATE by the following
calls:

InitializeObjectAttributes(&FileAttributes,&eskdFileObject->cacheFileName,OBJ_KERNEL_HANDLE,NULL,NULL);

IoCreateFileSpecifyDeviceObjectHint(
&eskdFileObject->cacheFileHandle,
GENERIC_WRITE,
&FileAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OVERWRITE_IF,
FILE_NON_DIRECTORY_FILE,
NULL,
0,
CreateFileTypeNone,
NULL,
0,
devExt->AttachedToDeviceObject
);

  1. Not relevant to your question, but anyway: I suggest that you
    inverse the order of these two lines

pEvent1 = IoCreateSynchronizationEvent(NULL, &hSadowEvent);
if(eskdFileObject && eskdFileObject->cacheFileHandle) {

}

so that they become

if(eskdFileObject && eskdFileObject->cacheFileHandle) {
pEvent1 = IoCreateSynchronizationEvent(NULL, &hSadowEvent);

}

Reason: you use hSadowEvent and [more importantly]
call ZwClose(hSadowEvent) only within the
block-of-code-that uses-and-closes-hSadowEvent
so that you have a leak if the condition in your “if” is false.

2) Possibly relevant to your question: are you serializing (queueing)
your own writes?
Can it be that one of your own writes happens to [try to] start
when your other write is still being processed?

----- Original Message -----
From:
To: “Windows File Systems Devs Interest List”
Sent: Thursday, November 27, 2008 4:30 AM
Subject: [ntfsd] Shadow copy of file content in FS filter

>I whant to make copy of all files written to disk in the special folder. So
>I
> have my own file system filter driver, I create new file for shadow copy
> each
> time when dispatch routine for IRP_MJ_CREATE is called (with appropriate
> create options), and write to this file from dispatch routine for
> IRP_MJ_WRITE. I use IoCreateFileSpecifyDeviceObjectHint to create file and
> ZwWriteFile to write. But call to ZwWriteFile fails with
> STATUS_FILE_LOCK_CONFLICT status. Moreover, when I call ZwWriteFile, I
> often
> get same status in calls to low-level drivers (IoCallDriver for
> IRP_MJ_WRITE), so system make several attempts to write file before
> success.
> This behavior differs in depending on application which writes the file:
> explorer.exe always write data successfully to the main destination and to
> shadow copy, Mspaint always hangs, and notepad.exe writes big file after
> 2 -5
> attempts.
>
> My code:
>
> NTSTATUS EskdDispatchForWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
> {
> PESKD_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
> PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
> PFILE_OBJECT fileObject = pIrpStack->FileObject;
> PESKD_FILE_OBJECT eskdFileObject =
> GetFileObjectEntryByFileObject(fileObject);
> PIO_STACK_LOCATION pNewStack;
> IO_STATUS_BLOCK IoStatusBlock;
> KEVENT event;
> PKEVENT pEvent1;
> HANDLE hSadowEvent;
> NTSTATUS statusWrite;
> NTSTATUS statusCall;
> LARGE_INTEGER offset;
> ULONG length=0;
> void* writeBuffer;
>
>
> pEvent1=IoCreateSynchronizationEvent(NULL, &hSadowEvent);
>
> if (eskdFileObject && eskdFileObject->cacheFileHandle)
> {
>
> PRINT_DEBUG_EX(“Process: %x; %wZ; Buffer length
> %i”,PsGetCurrentProcessId(),&eskdFileObject->cacheFileName,
> pIrpStack->Parameters.Write.Length);
>
>
>
>
> statusWrite=STATUS_UNSUCCESSFUL;
>
> offset=pIrpStack->Parameters.Write.ByteOffset;
> length=pIrpStack->Parameters.Write.Length;
>
> PRINT_DEBUG_EX(“Offset %x”,offset);
>
> IoCopyCurrentIrpStackLocationToNext(Irp);
> KeInitializeEvent(&event, NotificationEvent, FALSE);
> IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)
> EskdCompleteIRP, &event, TRUE, TRUE, TRUE);
> statusCall = IoCallDriver(devExt->AttachedToDeviceObject, Irp);
> PRINT_DEBUG_EX(“IoCallDriver status %x”,statusCall);
>
> if(statusCall==STATUS_PENDING)
> {
> KeWaitForSingleObject(&event,
> Executive,
> KernelMode,
> FALSE,
> NULL );
> }
>
>
> if(Irp->MdlAddress)
> {
>
> writeBuffer=MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);
> PRINT_DEBUG(writeBuffer ? “Mdl mapped OK” : “Mdl mapped
> NULL”);
> }
> else
> {
> writeBuffer=Irp->UserBuffer;
> PRINT_DEBUG(writeBuffer ? “UserBuffer OK” : “UserBuffer
> NULL”);
> }
>
>
>
> //!!! This function cause the block
> statusWrite=ZwWriteFile(eskdFileObject->cacheFileHandle,
> hSadowEvent,
> NULL,
> NULL,
> &IoStatusBlock,
> writeBuffer,//Irp->AssociatedIrp.SystemBuffer,
> length ,
> &offset,
> NULL
> );
>
> PRINT_DEBUG_EX(“ZwWriteFile status %x”,statusWrite);
>
> if(statusWrite==STATUS_PENDING)
> {
> KeWaitForSingleObject(pEvent1,
> Executive,
> KernelMode,
> FALSE,
> NULL );
> }
>
>
> ZwClose(hSadowEvent);
>
> IoCompleteRequest(Irp, IO_NO_INCREMENT);
>
>
> return Irp->IoStatus.Status;
>
> }
> else
> {
> return EskdPassThrough(DeviceObject,Irp);
> }
>
> }
>
> File handle is opened in dispatch routine for IRP_MJ_CREATE by the
> following
> calls:
>
> InitializeObjectAttributes(&FileAttributes,&eskdFileObject->cacheFileName,OBJ_KERNEL_HANDLE,NULL,NULL);
>
> IoCreateFileSpecifyDeviceObjectHint(
> &eskdFileObject->cacheFileHandle,
> GENERIC_WRITE,
> &FileAttributes,
> &IoStatusBlock,
> NULL,
> FILE_ATTRIBUTE_NORMAL,
> FILE_SHARE_READ|FILE_SHARE_WRITE,
> FILE_OVERWRITE_IF,
> FILE_NON_DIRECTORY_FILE,
> NULL,
> 0,
> CreateFileTypeNone,
> NULL,
> 0,
> devExt->AttachedToDeviceObject
> );
>
>
> —
> NTFSD 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@comcast.net
> To unsubscribe send a blank email to xxxxx@lists.osr.com

Alex, thank you for the answer

  1. yeah, I should fix this memory leak!
  2. In general, it is possible that several ZwWriteFile will be called in the same time, if several processes will write the data and my dispatch routine will be called. I think this should not result in any issues anyway. But log file displays that it is called only once actually, so it is not the cause of my issue surely.
    My own writes are not dispatched by EskdDispatchForWrite, because shadow-copy file is opened with IoCreateFileSpecifyDeviceObjectHint and low-level driver is specifyed as destination for shadow-copy requests.

New data related to the issue is available:

ZwWriteFile returns STATUS_FILE_LOCK_CONFLICT only when it is called twice for the same file for different offset, so when I changed statusWrite=ZwWriteFile(…); to:

offset.LowPart=eskdFileObject->debug_off;//initialized as 0
offset.HighPart=0;
statusWrite=ZwWriteFile(eskdFileObject->cacheFileHandle,
hSadowEvent,
NULL,
NULL,
&IoStatusBlock,
debug_static_buffer,
50,
&offset,
NULL
);
eskdFileObject->debug_off+=OFFSET_INCREMENT;

Applications that write the files hangs if OFFSET_INCREMENT=50, and doesn’t hang if OFFSET_INCREMENT=0.

Requests don’t hang if they are performed in the system context (not in caller-process context). When explorer.exe performs copy operation, EskdDispatchForWrite is called by process with PID 4 (system) so it doesn’t hang.

> But log file displays that it is called only once actually,

so it is not the cause of my issue surely.
Hmmm…
You know better.

My logic is simple: IIUYC, you are the one and only
owner of the shadow device, so it is your code that either
reads or writes or pages in or out while you are writing.

Hinted open does not change the picture: you go down but
you enter the elevator on the 5th floor, not on the top one
(say, 11th) as everyone else, but everyone comes to the
5th, 4th, … floors sooner or later anyway, and you have
a ride to share.

So if you have simultaneous 11th-floor and 5th floor
writes, then “Huston, we have a problem.”

Does !lock or its friends say anything in plain russian?

----- Original Message -----
From:
To: “Windows File Systems Devs Interest List”
Sent: Thursday, November 27, 2008 7:20 AM
Subject: RE:[ntfsd] Shadow copy of file content in FS filter

> Alex, thank you for the answer
> 1) yeah, I should fix this memory leak!
> 2) In general, it is possible that several ZwWriteFile will be called in
> the same time, if several processes will write the data and my dispatch
> routine will be called. I think this should not result in any issues
> anyway. But log file displays that it is called only once actually, so it
> is not the cause of my issue surely.
> My own writes are not dispatched by EskdDispatchForWrite, because
> shadow-copy file is opened with IoCreateFileSpecifyDeviceObjectHint and
> low-level driver is specifyed as destination for shadow-copy requests.
>
> —
> NTFSD 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@comcast.net
> To unsubscribe send a blank email to xxxxx@lists.osr.com

Hi,I resolved the issue today!

NTFS driver returns status STATUS_FILE_LOCK_CONFLICT after receiving certain write requests to files with zerro size. So if the primary request is related to already exist file, I should get size of this file in dispatch routine for IRP_MJ_CREATE and set new size of shadow copy file to this value. It stoped to hang after I implemented this functionality.

Does anyone have an idea why STATUS_FILE_LOCK_CONFLICT returned for some reqests to empty file objects? (I don’t quite understand what parameters of request cause this issue.)

I would be little bit nervous to use ZwXXX like functions being on the stack and especially in (paging) non-cached write path. Still you didn’t get call from Cc/Mm at APC level? Furthermore your code shouldn’t cause any page fault. e.g. Is eskdFileObject in non-paged pool? Is whole code processing write path non-pageable? Zw functions don’t fulfill such criteria. Imagine scenario when systems lacks the pages and Mm’s Mapped/Modified Page Writer tries to save content of dirty page so it can satisfy page request. When you cause page-fault you are in deadlock. Other source of deadlock can be Cache Write Throttling. Your write to shadow copy might be throttled (blocked for indefinite time), because it is cached write.

I think you should pass-down cached writes and handle only (paging) non-cached writes and write into non-cached shadow copy.

Hi, Bronislav

Now I changed ZwWriteFile to code that construct my own IRP with IoBuildSynchronousFsdRequest and send it to low-level driver. You are right that this way is little less nervouse. Actually I get BSODs sometimes, but I am not sure it that the bug is in discussed function EskdDispatchForWrite - I am investigating.

I call ZwSetInformationFile from IRP_MJ_CREATE and IRP_MJ_CLOSE dispatch routines - do you think this is dengerouse?

The IRP_MJ_CREATE is OK. The IRP_MJ_CLOSE can be called at arbitrary context and at APC_LEVEL. Lookup for table in MSDN called “Dispatch Routine IRQL and Thread Context” for other dispatch routines.

-bg

STATUS_FILE_LOCK_CONFLICT is “unable to write, but not an error” code that can be returned to a Lazy Writer (CcWriteBehind, I believe). This will make CM “retry” writing that page(s) later.

Yes, my problem was that I intercepted requests from Lazy Writer, wich is passed through filter driver with IRP_PAGING_IO flag set. I guess this should not be done - only original write requests should be splited for shadowing.
Now my problem is that some requests are not IRPs, but FastIoWrite calls. If I fail each FastIoWrite call (by returning FALSE in filter driver FastIoWrite without calling low-level driver), I get all the stuff as IRP_MJ_WRITE request and can make shadow copy. What do you think about such forced break of FastIoCall - is not it dangerous or slow down the system?

There is a fundamental flaw in this approach: you’re gonna be missing memory mapped writes, that always come as paging I/O only and may (starting with Vista, I believe) come in the context of Lazy Writer thread, and not in context of Mm flushing thread.

Vladimir, thank you for the advise. What do you mean by memory mapped writes - writes related to flushing files mapped by IRP_MJ_LOCK_CONTROL? When I monitor requests from Lazy Writer passed through filter driver, I don’t detect IRP_MJ_WRITE for this kind of files (ex. MS Office file operations), but IRP_MJ_LOCK_CONTROL only (on XP SP2). Do you have an idea how to catch writes related to memory mapped files and distingush them from other data flow from Lazy Writer?
And I still have unresolved question about enforced fail of FastIoWrite: is this allowed to return FALSE in FastIoWrite to get all requests as IRP?

Memory mapped writes are writes coming from Memory Manager flushing pages modified in memory mapped view of a file. It has nothing to do with the lock control. All Mm writes are paging writes and (generally) you can’t distinguish them fom Cm writes.
As for FALSE returned from FastIoWrite, it is allowed and it will force the write request to go the IRP path.

Alexey,

only original write requests should be splitted for shadowing.
Now my problem is that some requests are not IRPs, but FastIoWrite calls. If I
fail each FastIoWrite call (by returning FALSE in filter driver FastIoWrite
without calling low-level driver)

Absolutely not true. Did you notice my advice below? It seems that you are taking exactly opposite approach. Simply let fast-io writes + cached writes pass-through and concentrate just on non-cached writes. It doesn’t matter if it is paging or not. Paging writes are always non-cached.

bg>I think you should pass-down cached writes and handle only (paging) non-cached
bg> writes and write into non-cached shadow copy.

The problem here is that you cannot use cached file while you are processing paging write. It causes recursion in Cache Manager. Your write might be throttled and you cause deadlock in Lazy Writer thread. The FSD can distinguish Lazy Writer because it calls something like AcquireForLazyWriter CC callback. Filters have no chance to intercept this callback, but I guess you can evaluate TopLevelIrp value. If TopLevelIrp != NULL at FSD dispatch entry, it means that executing resources in FCB were acquired, so FSD must not lock it for now. There are special values which are assigned into TopLevelIrp in case FSD is caled from FastIo, Cache Manager, MemoryManager. Take look into WDK headers I don’t know them by heart.

TopLevelIrp is thread specific variable, so it plays role here. You have to either write into shadow copy from different thread, or you can use hack - save TopLevelIrp and do your write and restore it back. The first approach is also problematic as at the arbitrary thread context you shouldn’t wait. Take look on KeWaitForSingleObject.

You should consider mini-filter model.

-bg

Hi, Bronislav, Vladimir

bg>I think you should pass-down cached writes and handle only (paging) non-cached
bg> writes and write into non-cached shadow copy.

Now after a lot of troubles I can understand what you are saying. So I found out that cached writes are easier to handle. But missing of memory mapped writes is a real problem when I use this approach. Could you please explain, are there other reasons for intercepting paged IO and ignore non-paged? I don’t whant to handle paged IO so much because this means MDL-handling, pooling shadow writes to helper thread, etc… - so my desire to find some other way is quite understandable :slight_smile: But what will I do with memory mapped files, yaeh…

Alexey:
In general, you can watch for and shadow-copy non-cached write IRPs (including paging ones). However, when you do your shadow-writes you MUST do it non-cached, otherwise you will cause CM deadlock on CcCanIWrite (as Bronislav has mentioned). To do that properly, you must open your “shadow” storage for non-buffered, write-through access (which will force you to align offset / size of your writes to sector size) and make sure that that’s the only mode your shadow storage is opened.

Thank you, now I am investigating cached writes monitoring, I will try to implement non-cached shadow writes and return with results.
I also tryed to use file mapping while dispatching IRP_MJ_WRITE as bypass way to make cache writes. This seems to be working with FAT, but I get bluescreens with NTFS (all the time when ZwCreateSection is not commented out). Do you think using this approach is totally impssible? Code for writing via memory mapping:

BOOLEAN DispatchForIrpMjWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
//…
PESKD_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT fileObject = pIrpStack->FileObject;
PESKD_FILE_OBJECT eskdFileObject = GetFileObjectEntryByFileObject(fileObject);
LARGE_INTEGER ll;
LARGE_INTEGER li;
LARGE_INTEGER lf;
ULONG i0;

if(eskdFileObject && eskdFileObject->cacheFileHandle && (Irp->Flags & IRP_PAGING_IO))
{

FsRtlGetFileSize(fileObject,&lf);
//up-rounded file size
lf.QuadPart=(lf.QuadPart+ 16*PAGE_SIZE - 1)&(~((LONGLONG)(16*PAGE_SIZE-1)));

if(Irp->MdlAddress)
{
writeBuffer=MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);
}
else
{
writeBuffer=Irp->UserBuffer;
}

//THIS IS JUST SECTION OFFSET AND SIZE CALCULATION
ll.QuadPart=pIrpStack->Parameters.Write.ByteOffset.QuadPart;
size=pIrpStack->Parameters.Write.Length;
ll.QuadPart=ll.QuadPart&(~((LONGLONG)(16*PAGE_SIZE-1)));//down-rounded offset of the block
li.QuadPart=pIrpStack->Parameters.Write.ByteOffset.QuadPart-ll.QuadPart;
i0=li.LowPart;
size+=i0;//beagining of the section was extended, so extend size
size=((ULONG)size+ 16*PAGE_SIZE - 1)&(~((ULONG)(16*PAGE_SIZE-1)));//up-rounded size of the block
li.QuadPart=ll.QuadPart+(LONGLONG)size;//up-rounded end of the block
if(lf.QuadPart

<li.quadpart> lf.QuadPart=li.QuadPart;//maximium expected offset for this file

//try to use undocumented NtExtendSection instead

if(eskdFileObject->sectionHandle!=NULL && eskdFileObject->sectionSize.QuadPart<lf.quadpart> {
PRINT_DEBUG(“Need to close section”);
ZwClose(eskdFileObject->sectionHandle);
eskdFileObject->sectionHandle=NULL;
}

if(eskdFileObject->sectionHandle==NULL)
{
eskdFileObject->sectionSize.QuadPart=lf.QuadPart;
InitializeObjectAttributes(&SectionAttributes,NULL,OBJ_KERNEL_HANDLE,NULL,NULL);
s=ZwCreateSection(&eskdFileObject->sectionHandle,SECTION_ALL_ACCESS,&SectionAttributes,
&eskdFileObject->sectionSize,PAGE_READWRITE,SEC_COMMIT,eskdFileObject->cacheFileHandle);
}

if(eskdFileObject->sectionHandle!=NULL)
{

s=ZwMapViewOfSection(eskdFileObject->sectionHandle,NtCurrentProcess(),&v,0,0,
&ll,
&size,
ViewUnmap,
0,//0x400000,//MEM_PHYSICAL
PAGE_READWRITE);

memcpy((char*)v+i0,writeBuffer,pIrpStack->Parameters.Write.Length);
s=ZwUnmapViewOfSection(NtCurrentProcess(), v);

PRINT_DEBUG_EX(“Unmapping status %x”,s);
}
return TRUE;
}

}</lf.quadpart></li.quadpart>

I would forget any section mappings for the start, and use the usual write paths instead.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntfsd…
> Thank you, now I am investigating cached writes monitoring, I will try to implement non-cached shadow writes and return with results.
> I also tryed to use file mapping while dispatching IRP_MJ_WRITE as bypass way to make cache writes. This seems to be working with FAT, but I get bluescreens with NTFS (all the time when ZwCreateSection is not commented out). Do you think using this approach is totally impssible? Code for writing via memory mapping:
>
> BOOLEAN DispatchForIrpMjWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
> {
> //…
> PESKD_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
> PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
> PFILE_OBJECT fileObject = pIrpStack->FileObject;
> PESKD_FILE_OBJECT eskdFileObject = GetFileObjectEntryByFileObject(fileObject);
> LARGE_INTEGER ll;
> LARGE_INTEGER li;
> LARGE_INTEGER lf;
> ULONG i0;
>
> if(eskdFileObject && eskdFileObject->cacheFileHandle && (Irp->Flags & IRP_PAGING_IO))
> {
>
> FsRtlGetFileSize(fileObject,&lf);
> //up-rounded file size
> lf.QuadPart=(lf.QuadPart+ 16PAGE_SIZE - 1)&(~((LONGLONG)(16PAGE_SIZE-1)));
>
> if(Irp->MdlAddress)
> {
> writeBuffer=MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);
> }
> else
> {
> writeBuffer=Irp->UserBuffer;
> }
>
> //THIS IS JUST SECTION OFFSET AND SIZE CALCULATION
> ll.QuadPart=pIrpStack->Parameters.Write.ByteOffset.QuadPart;
> size=pIrpStack->Parameters.Write.Length;
> ll.QuadPart=ll.QuadPart&(~((LONGLONG)(16PAGE_SIZE-1)));//down-rounded offset of the block
> li.QuadPart=pIrpStack->Parameters.Write.ByteOffset.QuadPart-ll.QuadPart;
> i0=li.LowPart;
> size+=i0;//beagining of the section was extended, so extend size
> size=((ULONG)size+ 16
PAGE_SIZE - 1)&(~((ULONG)(16PAGE_SIZE-1)));//up-rounded size of the block
> li.QuadPart=ll.QuadPart+(LONGLONG)size;//up-rounded end of the block
> if(lf.QuadPart<li.quadpart>> lf.QuadPart=li.QuadPart;//maximium expected offset for this file
>
> //try to use undocumented NtExtendSection instead
>
> if(eskdFileObject->sectionHandle!=NULL && eskdFileObject->sectionSize.QuadPart<lf.quadpart>> {
> PRINT_DEBUG(“Need to close section”);
> ZwClose(eskdFileObject->sectionHandle);
> eskdFileObject->sectionHandle=NULL;
> }
>
> if(eskdFileObject->sectionHandle==NULL)
> {
> eskdFileObject->sectionSize.QuadPart=lf.QuadPart;
> InitializeObjectAttributes(&SectionAttributes,NULL,OBJ_KERNEL_HANDLE,NULL,NULL);
> s=ZwCreateSection(&eskdFileObject->sectionHandle,SECTION_ALL_ACCESS,&SectionAttributes,
> &eskdFileObject->sectionSize,PAGE_READWRITE,SEC_COMMIT,eskdFileObject->cacheFileHandle);
> }
>
> if(eskdFileObject->sectionHandle!=NULL)
> {
>
> s=ZwMapViewOfSection(eskdFileObject->sectionHandle,NtCurrentProcess(),&v,0,0,
> &ll,
> &size,
> ViewUnmap,
> 0,//0x400000,//MEM_PHYSICAL
> PAGE_READWRITE);
>
> memcpy((char
)v+i0,writeBuffer,pIrpStack->Parameters.Write.Length);
> s=ZwUnmapViewOfSection(NtCurrentProcess(), v);
>
> PRINT_DEBUG_EX(“Unmapping status %x”,s);
> }
> return TRUE;
> }
>
>
> }
></lf.quadpart></li.quadpart>

Well, I have implemented non-cached shadow writes from non-cached requests dispatcher:

  1. Shadow copy file is opened with FILE_NO_INTERMEDIATE_BUFFERING flag
  2. Shadow write requests are sent with IRP_NOCACHE flag, and only when dispatching IRP with IRP_NOCACHE flag

For this case, I got STATUS_FILE_LOCK_CONFLICT error for each shadow write request. This happend when size of shadow copy file was less then write offset. It seems to me that file size can’t be extended when dispatching non-cached writes. To fix this, I implemented extending of shadow copy file size on each IRP_MJ_SET_INFORMATION/FileEndOfFileInformation and on each cached write request. This partially fixed the problem, but now I still have STATUS_FILE_LOCK_CONFLICT for about one percent of write requests to shadow copy, and I can’t find any regularity in this failures.
I tryed to return error to the caller or just send write request again, but this results in infinit loop of calls.
So the following question should be asked: what is the other cause of STATUS_FILE_LOCK_CONFLICT, except resolved issue with incorrect file size?