none
Creating a new request in kmdf? RRS feed

  • Question

  • Hi, 
    Would it be possible to forward a read WDF request that my driver 
    (driver 1) received from an upper layer to another driver (driver 2) 
    that is part of a different driver stack? I just want to forward the 
    original request and I do not want to create a new WDF request. Is 
    this possible? If YES how? If NO why and what should I have to do? 

    My driver is a KMDF driver. 

    In the WDM world, this scenario would require driver 1 
    1. pend the oringal request 
    2. creating a new IRP 
    3. format the new IRP it accordingly 
    4. Set a completion routine for the new IRP 
    5. send new IRP to the driver 2 and wait for it to be completed by 
    driver 2 and 
    6. complete the original request (I have omitted the cancel part for 
    simplicity). 
    This is required since the current IRP that driver 1 recived from 
    upper layer might have different number of stack locations than what 
    is needed by the driver stack 2. 

    I wonder how this scenario translates into the KMDF world. Does it 
    require driver 1 to create a new WDF request and send it to driver 2? 
    Or the framework can handle this internally by creating a new WDF 
    request for the driver stack 2, send it down and then complete my 
    originaly request when then new one gets completed by driver stack 2? 

    Monday, December 9, 2013 7:21 AM

Answers

  • This model has to be translated the WDF framework does not automatically create a new IRP with the correct number of stack locations.

    It should be noted that there is a trick that has been used for years so that creating a new IRP is not needed.  Assuming that both of the stacks are present at the time of the creation of the device for your driver you set the StackSize field of the DEVICE_OBJECT to the larger of the two stacks requirements plus 1.  Since you can get the StackSize for the targests from their DEVICE_OBJECT's. 

    Note this only works at device creation time, once you have cleared the DO_DEVICE_INITIALIZING all bets are off since a device may be layered on top of your.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Monday, December 9, 2013 11:51 AM
  • Just get the buffer and initiate a new request using the buffer from the initial request.  Since your disk offset, target etc are all different, there is nothing else you need to worry about.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Monday, December 9, 2013 3:16 PM

All replies

  • This model has to be translated the WDF framework does not automatically create a new IRP with the correct number of stack locations.

    It should be noted that there is a trick that has been used for years so that creating a new IRP is not needed.  Assuming that both of the stacks are present at the time of the creation of the device for your driver you set the StackSize field of the DEVICE_OBJECT to the larger of the two stacks requirements plus 1.  Since you can get the StackSize for the targests from their DEVICE_OBJECT's. 

    Note this only works at device creation time, once you have cleared the DO_DEVICE_INITIALIZING all bets are off since a device may be layered on top of your.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Monday, December 9, 2013 11:51 AM
  •  I did not get it. I will ask you specifically. Suppose a disk read request comes to my kmdf based filter driver and I read it from the same disk. Now just before completing the request I want to write the same data to disk2 so for that I need to create a new request and I want all fields to be initialized and then forward request to write. Is there any api which will copy the old request field to new request field ?or some thing else I am suppose to do? 
    Monday, December 9, 2013 1:00 PM
  • Just get the buffer and initiate a new request using the buffer from the initial request.  Since your disk offset, target etc are all different, there is nothing else you need to worry about.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Monday, December 9, 2013 3:16 PM
  • My driver is kmdf based filter driver. I know that WdfRequestCreate create new request with iotarget given as one of the parameter. Now what else do I need to initialize in a request for writing into this iotarget with that buffer. how would framework get to know that the request I have created with WdfRequestCreate() is a write request with buffer , at some address that I will give  and stack location etc. ? Are there some sort of apis in kmdf which I need to use to tell framework to initialize rest of the field or I have to do it manually. 
    Wednesday, December 11, 2013 5:54 AM
  • After you create the request simply use WdfIoTargetFormatRequestForWrite to fill in the data.


    Don Burn Windows Filesystem and Driver Consulting Website: http://www.windrvr.com Blog: http://msmvps.com/blogs/WinDrvr

    Wednesday, December 11, 2013 11:56 AM
  • If I create the request just once in EvtDriverDeviceAdd  for particular disk and reuse this request by just reformatting using  WdfIoTargetFormatRequestForWrite and putting the received buffer from disk1 and sending again and again to disk2 then how would I set the completion routine because in this case I can not delete request or I can not use WdfRequestDelete ?? because it will delete the request and I will not be able to use WdfRequestReuse ?or   should I use only WdfRequestComplete and then later on just use WdfRequestReuse?? or I need not to set completion routine? 
    Thursday, December 12, 2013 6:05 AM
  • you can set a completion routine. a completion routine != deletion nor does it mean the request will be completed to the higher layer. you need to call WdfRequestComplete explicitly for that to happen.

    for a driver created request the pattern would be

    a) allocate

    b) format

    c) set a completion routine

    d) send it

    e) in the completion routine, either delete the request or Reuse() it, format it again, set a c.r., send it again


    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Thursday, December 12, 2013 8:09 AM
  • Thanks Doron

    >After you create the request simply use WdfIoTargetFormatRequestForWrite to fill in the data.

    Suppose in my read completion routine just before wdfrequestcomplete of original request, if the get the memory object using WdfRequestRetrieveOutputMemory  and then I create new request , format the request using WdfIoTargetFormatRequestForWrite and put memory object that I got above to write into disk2 , set completion routine  and then send it.

    Read completion routine{

    WdfRequestRetrieveOutputMemory(original request)

    Create new request

    format the request 

    set completion routine

    wdfrequestsend

    wdfrequestcomplete(original request)

    }

    In this case if I send the request then original request will be completed before the new request completes so memory object will not be available so new request will not be completed, Am I right ??

    If I use WdfIOTargetSendWriteSunchronously() instead of above. will this work for me because first new request will be completed then original request.?

    Or both methods are wrong and there is another way around? 

    Thursday, December 12, 2013 10:42 AM
  • you did not reply. Please reply this is very imp for me to know.
    Friday, December 13, 2013 8:12 AM
  • when you complete a request, both the input and output buffer of that request are freed. it doesn't matter if you put the buffer into another request, the original irp owns the buffers' lifetime and that lifetime is guarded by the request's completion. if you want to send the read on the original and then use that buffer as part of the write with a new request, you must wait for that new request to complete before completing the original. KMDF verifier should catch the error of completing a request while having another request using that original request's buffers

    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Friday, December 13, 2013 8:28 AM
  • 1. So for that I need to use WdfIoTargetSend WriteSynchronously.??

    2. Suppose if I want the request to be independently Completed then I could use new buffer instead and put the read data into it and then format request using  WdfIoTargetFormatRequestForWrite then send it. So now original request does not have to wait for new request to be completed?

    Sunday, December 15, 2013 1:53 PM
  • You don't have to send synchronously, you can send async and when the new request's completion routine is called, you complete the original request. If you want to complete the original without waiting for the new request to complete then allocate the same size buffer and copy the contents over

    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Sunday, December 15, 2013 4:18 PM
  • I followed you and did the same as discussed but I am getting fatal error in my write completion routine that I used it with my new request creation.

    VOID NewWriteCompletionRoutine(IN WDFREQUEST Request,
        IN WDFIOTARGET Target,
        IN PWDF_REQUEST_COMPLETION_PARAMS Params,
        IN WDFCONTEXT Context){

    WDFMEMORY memoryobject;
    WdfRequestRetrieveInputMemory(Request,&memoryobject);
    WdfObjectDelete(Request);
    WdfObjectDelete(memoryobject);

    }

    when WdfRequestRetrieveInputMemory gets called in my completion routine it generates fatal error :

    DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
    An attempt was made to access a pageable (or completely invalid) address at an
    interrupt request level (IRQL) that is too high.  This is usually
    caused by drivers using improper addresses.
    If kernel debugger is available get stack backtrace.
    Arguments:
    Arg1: 00000006, memory referenced
    Arg2: 00000002, IRQL
    Arg3: 00000000, value 0 = read operation, 1 = write operation
    Arg4: 8be2852b, address which referenced memory

    Debugging Details:
    ------------------


    READ_ADDRESS:  00000006 

    CURRENT_IRQL:  2

    FAULTING_IP: 
    Wdf01000!FxDeviceToMx::GetHandle+2
    8be2852b 66394806        cmp     word ptr [eax+6],cx

    DEFAULT_BUCKET_ID:  WIN7_DRIVER_FAULT

    BUGCHECK_STR:  0xD1

    PROCESS_NAME:  System

    TRAP_FRAME:  807d5ad4 -- (.trap 0xffffffff807d5ad4)
    ErrCode = 00000000
    eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=92dcd2b8 edi=807d5b60
    eip=8be2852b esp=807d5b48 ebp=807d5b6c iopl=0         nv up ei pl zr na pe nc
    cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00210246
    Wdf01000!FxDeviceToMx::GetHandle+0x2:
    8be2852b 66394806        cmp     word ptr [eax+6],cx      ds:0023:00000006=????
    Resetting default scope

    LAST_CONTROL_TRANSFER:  from 826ece71 to 8267b394

    STACK_TEXT:  
    807d569c 826ece71 00000003 dcd02a61 00000065 nt!RtlpBreakWithStatusInstruction
    807d56ec 826ed96d 00000003 00000006 8be2852b nt!KiBugCheckDebugBreak+0x1c
    807d5ab4 826567eb 0000000a 00000006 00000002 nt!KeBugCheck2+0x68b
    807d5ab4 8be2852b 0000000a 00000006 00000002 nt!KiTrap0E+0x2cf
    807d5b44 8be30378 6d232d40 6d232d40 807d5bbc Wdf01000!FxDeviceToMx::GetHandle+0x2
    807d5b6c 8be6a50d 807d5b94 807d5ba8 807d5ba0 Wdf01000!FxRequest::GetMemoryObject+0x2d6
    807d5b98 8c3a1d57 85e9ad48 92dcd2b8 807d5bbc Wdf01000!imp_WdfRequestRetrieveInputMemory+0xe2
    807d5bac 8c3a09b3 6d232d40 807d5bbc 6d232d40 diskfilter!WdfRequestRetrieveInputMemory+0x27 [c:\program files\windows kits\8.0\include\wdf\kmdf\1.11\wdfrequest.h @ 1103]
    807d5bc0 8be2c419 6d232d40 7a160958 953b6314 diskfilter!NewWriteCompletionRoutine+0x13 [c:\users\rohan\documents\visual studio 2012\projects\diskfilter\diskfilter\wdffilter.cpp @ 932]
    807d5be8 8be29163 9375bae8 85e9f6a0 00000000 Wdf01000!FxRequestBase::CompleteSubmitted+0xf1
    807d5c14 8be2923c 85e9f6a0 85ec04b0 807d5c4c Wdf01000!FxIoTarget::RequestCompletionRoutine+0x140
    807d5c24 82699896 00000000 9375bae8 92dcd2b8 Wdf01000!FxIoTarget::_RequestCompletionRoutine+0x33
    807d5c4c 82678b33 00000000 9375bae8 85ec04b0 nt!IopUnloadSafeCompletion+0x45
    807d5c90 8bf442ac 807d5ce0 85e9e5a8 00000000 nt!IopfCompleteRequest+0x128
    807d5cac 8bf41ba7 85e9e5a8 807d5ce0 85e9e4b0 partmgr!PmSplitAndRedirect+0x9f
    807d5cec 828307b5 00e9e4f0 00000000 8514bd48 partmgr!PmNotificationWorkItem+0x28b
    807d5d00 8267df2b 85e9e4b0 00000000 8514bd48 nt!IopProcessWorkItem+0x23
    807d5d50 8281e66d 00000000 dcd0211d 00000000 nt!ExpWorkerThread+0x10d
    807d5d90 826d00d9 8267de1e 00000000 00000000 nt!PspSystemThreadStartup+0x9e
    00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x19


    STACK_COMMAND:  kb

    FOLLOWUP_IP: 
    diskfilter!WdfRequestRetrieveInputMemory+27 [c:\program files\windows kits\8.0\include\wdf\kmdf\1.11\wdfrequest.h @ 1103]
    8c3a1d57 5d              pop     ebp

    FAULTING_SOURCE_LINE:  c:\program files\windows kits\8.0\include\wdf\kmdf\1.11\wdfrequest.h

    FAULTING_SOURCE_FILE:  c:\program files\windows kits\8.0\include\wdf\kmdf\1.11\wdfrequest.h

    FAULTING_SOURCE_LINE_NUMBER:  1103

    FAULTING_SOURCE_CODE:  
      1099:     WDFMEMORY* Memory
      1100:     )
      1101: {
      1102:     return ((PFN_WDFREQUESTRETRIEVEINPUTMEMORY) WdfFunctions[WdfRequestRetrieveInputMemoryTableIndex])(WdfDriverGlobals, Request, Memory);
    > 1103: }
      1104: 
      1105: //
      1106: // WDF Function: WdfRequestRetrieveOutputMemory
      1107: //
      1108: typedef


    SYMBOL_STACK_INDEX:  7

    SYMBOL_NAME:  diskfilter!WdfRequestRetrieveInputMemory+27

    FOLLOWUP_NAME:  MachineOwner

    MODULE_NAME: diskfilter

    IMAGE_NAME:  diskfilter.sys

    DEBUG_FLR_IMAGE_TIMESTAMP:  52af0c6d

    FAILURE_BUCKET_ID:  0xD1_diskfilter!WdfRequestRetrieveInputMemory+27

    BUCKET_ID:  0xD1_diskfilter!WdfRequestRetrieveInputMemory+27

    Followup: MachineOwner

    --------------------------------------------------------------------------------------------

    I did not get it why this error is generated as I did not change the IRQL level, is it because of I created the request and memory object was not attached to it?  because I retrive the output memory handle in my original read request completion routine there I did not get this fatal error and I also think that when I format the new request it attaches the memory object with it?? Please help me to solve this confusion and error.

    Or if the set my new request object as the parent of memory object handle
    and then if I delete the new request object in my completion routine then it will also delete memory object.??
    Tuesday, December 17, 2013 1:57 PM
  • WdfRequestRetrieveInput/OutputMemory require a current valid stack location in the request. driver created requests do not have a current valid irp stack location, so these calls are not appropriate for a driver created request. they are valid for a request presented to you on a WDFQUEUE.

    to get to the WDFMEMORY you allocated, you can either store it in the context parameter OR retrieve it from PWDF_REQUEST_COMPLETION_PARAMS Params


    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Tuesday, December 17, 2013 4:09 PM