Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results
The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.
Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/
Hello,
I'm facing a problem that I don't know how to overcome.
I have this code snippet, it just lock some part of a file (c:\lock_test.txt) and then tries to write on some bytes of this part. It runs well, no problems.
h_file=CreateFileA(p_file_name, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL); LockFile(h_file, 0, 0, 1, 0); WriteFile(h_file, buff, 10, &ucb_written, NULL);
Then, I have a minifilter, that intercepts this WRITE request and posts it to a worker thread. The worker thread tries to perform some WRITE on this file using FltWriteFileEx(). In the sample I just issue the same WRITE request I received and then complete the I/O.
/*------------------------------------------------------------------------------ IRPFlagsToIoOperationFlags ------------------------------------------------------------------------------*/ FLT_IO_OPERATION_FLAGS IRPFlagsToIoOperationFlags(ULONG uIRPFlags) { FLT_IO_OPERATION_FLAGS ioFlags=0; if (uIRPFlags&IRP_NOCACHE) { ioFlags=FLTFL_IO_OPERATION_NON_CACHED; } if (uIRPFlags&IRP_PAGING_IO) { ioFlags=FLTFL_IO_OPERATION_PAGING; } if (uIRPFlags&IRP_SYNCHRONOUS_PAGING_IO) { ioFlags=FLTFL_IO_OPERATION_SYNCHRONOUS_PAGING; } return ioFlags; } /*------------------------------------------------------------------------------ pWriteCB ------------------------------------------------------------------------------*/ void pWriteCB(PFLT_DEFERRED_IO_WORKITEM pDW, PFLT_CALLBACK_DATA pCBData, void *pCtx) { NTSTATUS rc; ULONG ucbWritten=0; rc=FltWriteFileEx( pCBData->Iopb->TargetInstance, pCBData->Iopb->TargetFileObject, &pCBData->Iopb->Parameters.Write.ByteOffset, pCBData->Iopb->Parameters.Write.Length, NULL, IRPFlagsToIoOperationFlags(pCBData->Iopb->IrpFlags), &ucbWritten, NULL, NULL, &pCBData->Iopb->Parameters.Write.Key, pCBData->Iopb->Parameters.Write.MdlAddress); __DBG_ERR("Write request ended with 0x%x, bytes written %u.\n", rc, ucbWritten); pCBData->IoStatus.Status=rc; pCBData->IoStatus.Information=ucbWritten; FltCompletePendedPreOperation(pCBData, FLT_PREOP_COMPLETE, NULL); FltFreeDeferredIoWorkItem(pDW); } DECLARE_CONST_UNICODE_STRING(usLockTest, L"\\device\\harddiskvolume3\\lock_test.txt"); /*------------------------------------------------------------------------------ WritePreOp ------------------------------------------------------------------------------*/ FLT_PREOP_CALLBACK_STATUS WritePreOp( _Inout_ PFLT_CALLBACK_DATA pCBData, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext) { NTSTATUS rc, ret; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; PFLT_DEFERRED_IO_WORKITEM pDW; rc=FltGetFileNameInformation(pCBData, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); if (rc!=STATUS_SUCCESS) { ret=FLT_PREOP_SUCCESS_NO_CALLBACK; goto end; } if (RtlEqualUnicodeString(&nameInfo->Name, &usLockTest, TRUE)==FALSE) { ret=FLT_PREOP_SUCCESS_NO_CALLBACK; goto end; } __DBG("Got a WRITE on %wZ.\n", nameInfo->Name); rc=FltLockUserBuffer(pCBData); if (rc!=STATUS_SUCCESS) { __DBG_ERR("Failed to lock UserBuffer %p.\n", pCBData->Iopb->Parameters.Write.WriteBuffer); ret=FLT_PREOP_SUCCESS_NO_CALLBACK; goto end; } pDW=FltAllocateDeferredIoWorkItem(); if (pDW==NULL) { __DBG_ERR("Failed allocating a WORKITEM.\n"); ret=FLT_PREOP_SUCCESS_NO_CALLBACK; goto end; } rc=FltQueueDeferredIoWorkItem(pDW, pCBData, pWriteCB, DelayedWorkQueue, NULL); if (rc!=STATUS_SUCCESS) { __DBG_ERR("Failed posting WORKITEM.\n"); FltFreeDeferredIoWorkItem(pDW); ret=FLT_PREOP_SUCCESS_NO_CALLBACK; goto end; } __DBG("THREAD IS %p.\n", pCBData->Thread); ret=FLT_PREOP_PENDING; end: if (nameInfo!=NULL) { FltReleaseFileNameInformation( nameInfo ); } return ret; }
But the FltWriteFileEx() ends with a FILE_LOCK_CONFLICT. I imagine it happends because I switch thread context.
I also tried to do FltAllocateCallbackDataEx() & FltPerformSynchronousIo() but it just ends the same way.
If I forward the posted request, it works well :
/*------------------------------------------------------------------------------ pWriteCB3 ------------------------------------------------------------------------------*/ void pWriteCB3(PFLT_DEFERRED_IO_WORKITEM pDW, PFLT_CALLBACK_DATA pCBData, void *pCtx) { UNREFERENCED_PARAMETER(pCtx); __DBG("Write request TRANSMITTED."); FltCompletePendedPreOperation(pCBData, FLT_PREOP_SUCCESS_NO_CALLBACK, NULL); FltFreeDeferredIoWorkItem(pDW); }
What can I do to no have this FILE_LOCK_CONFLICT ? Because I really need to post this request and then perform some other requests ...
Thank you !
Upcoming OSR Seminars | ||
---|---|---|
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead! | ||
Kernel Debugging | 30 January 2023 | Live, Online |
Developing Minifilters | 20 March 2023 | Live, Online |
Internals & Software Drivers | 17 April 2023 | Live, Online |
Writing WDF Drivers | 22 May 2023 | Live, Online |
Comments
I think that the problem is that there is an implied process in the CBD you get given in your PreWrite and issuing a FltWrite doesn't have a slot for it.
Is there any reason why you cannot, in your worker thread, just restart the CBD you get given in your PreWrite call?
If not - and I have no idea if this would work - you might get lucky by allocating the CBD you are going to use in the context of your pre-write, passing it to your worker thread, and FltPerformSynchronousIo-ing it there.
Thank you a lot for your reply Rod.
I tried to alter the "Thread" field of the CBD before calling FltPerformSynchronousIo() (even if it is const) but it didn't work.
What do you mean by "just restart the CBD you get given in your PreWrite call" ?
I just tried your idea of allocating the CBD in the pre-write and use it in the worker thread, but I get the same result.
If by "just restart the CBD you get given in your PreWrite call" you mean passing the CBD to FltPerformSynchronousIo(), it doesn't work.
FILTER VERIFIER checks this an issues an error :
No, I mean calling
FltCompletePendedPreOperation
withFLT_PREOP_SUCCESS_WITH_CALLBACK
Yes this works, but I want to send more than one I/O (READs and WRITEs).
I don't see a way to do this without getting FILE_LOCK_CONFLICT ....
I'm starting to wonder if it's not something the guys at Microsoft forgot... because there is no way to perform a FltReadFile() or a FltWriteFile() on a portion of a file that has been locked in a worker thread ...
If someone has any idea I am very interested !