Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTFSD

Before Posting...

Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


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/


FILE_LOCK_CONFLICT on FltWriteFileEx() from a worker Thread

benjibenji Member Posts: 19

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 !

Comments

  • rod_widdowsonrod_widdowson Member - All Emails Posts: 1,229

    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.

  • benjibenji Member Posts: 19

    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.

    typedef struct _FLT_CALLBACK_DATA {
      FLT_CALLBACK_DATA_FLAGS     Flags;
      PETHREAD                    Thread;
      PFLT_IO_PARAMETER_BLOCK     Iopb;
    

    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.

  • benjibenji Member Posts: 19

    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 :

    A filter is trying to use a callbackdata wich wasn't generated using FltAllocateCallbackData().
    
  • rod_widdowsonrod_widdowson Member - All Emails Posts: 1,229

    No, I mean calling FltCompletePendedPreOperation with FLT_PREOP_SUCCESS_WITH_CALLBACK

  • benjibenji Member Posts: 19

    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 ....

  • benjibenji Member Posts: 19

    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 !

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

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!
Writing WDF Drivers 12 September 2022 Live, Online
Internals & Software Drivers 23 October 2022 Live, Online
Kernel Debugging 14 November 2022 Live, Online
Developing Minifilters 5 December 2022 Live, Online