/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    InnerIo.c

Abstract:

    This module implements the read, write, and lockctrl routines for the proxy minirdr
Author:

    Joe Linn      [JoeLinn]      11-Oct-1994

Revision History:

--*/

#include "precomp.h"
#pragma hdrstop

//
//  The local debug trace level
//

#define Dbg                              (DEBUG_TRACE_READ)

#ifdef ALLOC_PRAGMA
#endif

NTSTATUS
MRxProxyBuildAsynchronousRequest(
    IN PRX_CONTEXT RxContext,
    IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL
    )

/*++

Routine Description:

    This routine builds an I/O Request Packet (IRP) suitable for a File System
    Driver (FSD) to use in requesting an I/O operation from a device driver.
    The request (RxContext->MajorFunction) must be one of the following request codes:

        IRP_MJ_READ
        IRP_MJ_WRITE
        IRP_MJ_DIRECTORY_CONTROL
        IRP_MJ_FLUSH_BUFFERS
        //IRP_MJ_SHUTDOWN (not yet implemented)


Arguments:

    CompletionRoutine - the IrpCompletionRoutine

Return Value:

    The function value is a pointer to the IRP representing the specified
    request.

--*/

{
    PIRP irp;
    PIO_STACK_LOCATION irpSp;
    ULONG MajorFunction = RxContext->MajorFunction;
    RxCaptureFcb; RxCaptureFobx;
    PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;

    PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext);

    PMRXPROXY_ASYNCENGINE_CONTEXT AsyncEngineContext =
                        (PMRXPROXY_ASYNCENGINE_CONTEXT)(pMRxProxyContext->AsyncEngineContext);

    PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
    PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(capFobx->pSrvOpen);
    //PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb);

    PDEVICE_OBJECT DeviceObject =  proxySrvOpen->UnderlyingDeviceObject;
    PFILE_OBJECT FileObject = proxySrvOpen->UnderlyingFileObject;

    LARGE_INTEGER ZeroAsLI;
    ULONG MdlLength = 0;

    PAGED_CODE();

    ASSERT (proxySrvOpen->UnderlyingFileObject);

    if (DeviceObject->Flags & DO_BUFFERED_IO) {
        //i cannot handled buffered_io devices....sigh
        return STATUS_INVALID_DEVICE_REQUEST;
    }


    RxDbgTrace(0, Dbg, ("MRxProxyBuildAsynchronousRequest %08lx %08lx len/off=%08lx %08lx\n",
                            RxContext,SrvOpen,
                            LowIoContext->ParamsFor.ReadWrite.ByteCount,
                            (ULONG)LowIoContext->ParamsFor.ReadWrite.ByteOffset));

    RxLog(("BuildAsyncIrp %lx %lx %lx %lx",
                            RxContext,SrvOpen,
                            LowIoContext->ParamsFor.ReadWrite.ByteCount,
                            (ULONG)LowIoContext->ParamsFor.ReadWrite.ByteOffset));

    ZeroAsLI.QuadPart = 0;

//    irp = IoBuildAsynchronousFsdRequest(
//              MajorFunction,
//              DeviceObject,
//              NULL,
//              0,
//              &ZeroAsLI,
//              NULL
//              );
//
//    if (!irp) {
//        return STATUS_INSUFFICIENT_RESOURCES;
//    }

    irp = IoAllocateIrp( DeviceObject->StackSize, FALSE ); //why not charge???
    if (!irp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // Set current thread for IoSetHardErrorOrVerifyDevice.
    //

    irp->Tail.Overlay.Thread = PsGetCurrentThread();

    //
    // Get a pointer to the stack location of the first driver which will be
    // invoked.  This is where the function codes and the parameters are set.
    //

    irpSp = IoGetNextIrpStackLocation( irp );  //ok4ioget
    irpSp->MajorFunction = (UCHAR) MajorFunction;
    irpSp->FileObject = FileObject;            //ok4->FileObj
    RxLog(("BuildAsyncIrpFo %lx %lx",RxContext,FileObject));

    {   BOOLEAN EnableCalls = CompletionRoutine!=NULL;

        IoSetCompletionRoutine(irp, CompletionRoutine, RxContext,
                                EnableCalls,EnableCalls,EnableCalls);
    }


    if ( (MajorFunction == IRP_MJ_READ) || (MajorFunction == IRP_MJ_WRITE) ) {

        // never paging io
        BOOLEAN PagingIo = FALSE;
        //BOOLEAN PagingIo =
        //    BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,LOWIO_READWRITEFLAG_PAGING_IO);

        irp->Flags |= IRP_NOCACHE;


        //
        // Set the parameters according to whether this is a read or a write
        // operation.  Notice that these parameters must be set even if the
        // driver has not specified buffered or direct I/O.
        //

        ASSERT (&irpSp->Parameters.Write.Key == &irpSp->Parameters.Read.Key);
        ASSERT (&irpSp->Parameters.Write.Length == &irpSp->Parameters.Read.Length);
        ASSERT (&irpSp->Parameters.Write.ByteOffset == &irpSp->Parameters.Read.ByteOffset);
        irpSp->Parameters.Read.Key = LowIoContext->ParamsFor.ReadWrite.Key;
        irpSp->Parameters.Read.ByteOffset.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
        irp->RequestorMode = KernelMode;

        irp->UserBuffer = RxLowIoGetBufferAddress(RxContext);

        MdlLength = RxContext->CurrentIrp->MdlAddress->ByteCount;

        if (PagingIo) {
            irpSp->Parameters.Read.Length = MdlLength;
        } else {
            irpSp->Parameters.Read.Length = LowIoContext->ParamsFor.ReadWrite.ByteCount;
        }

    } else if (MajorFunction == IRP_MJ_FLUSH_BUFFERS) {

        MdlLength = 0;
        //nothing else to do!!!

    } else {

        FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
        PVOID   Buffer = RxContext->Info.Buffer;
        PULONG  pLengthRemaining = &RxContext->Info.LengthRemaining;
        BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);

        ASSERT( MajorFunction == IRP_MJ_DIRECTORY_CONTROL );
        irpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY;
        //CODE.IMPROVEMENT it would be better to actually get the stuff out of the context.info
        irpSp->Parameters.QueryDirectory = RxContext->CurrentIrpSp->Parameters.QueryDirectory;
        ASSERT (
               (irpSp->Parameters.QueryDirectory.FileInformationClass == FileInformationClass)
            && (irpSp->Parameters.QueryDirectory.Length == *pLengthRemaining)
        );
        irpSp->Flags = RxContext->CurrentIrpSp->Flags;
        irp->UserBuffer = Buffer;
        MdlLength = *pLengthRemaining;

        if (Wait) {
            irp->Flags |= IRP_SYNCHRONOUS_API;
        }
    }

    // Build an mdl if necessary....

    if (MdlLength != 0) {
        irp->MdlAddress = IoAllocateMdl(irp->UserBuffer,MdlLength,
                                       FALSE,FALSE,NULL);
        if (!irp->MdlAddress) {
            //whoops.......sorry..........
            IoFreeIrp(irp);
            return(STATUS_INSUFFICIENT_RESOURCES);
        }

        MmBuildMdlForNonPagedPool(irp->MdlAddress);
    }

    //
    // Finally, return a pointer to the IRP.
    //

    AsyncEngineContext->CalldownIrp = irp;
    RxLog(("BAsyIrpX %lx %lx %lx %lx %lx %lx %lx",
                            RxContext,
                            irpSp->MajorFunction,
                            irpSp->Flags,
                            irpSp->Parameters.Others.Argument1,
                            irpSp->Parameters.Others.Argument2,
                            irpSp->Parameters.Others.Argument3,
                            irpSp->Parameters.Others.Argument4));
    return STATUS_SUCCESS;
}

//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//
//  The local debug trace level
//

#undef  Dbg
#define Dbg                              (DEBUG_TRACE_WRITE)

//everything else in here is ifdef'd out....also CODE.IMPROVEMENT we should change over
//to a common irp building routine in Rx. the code is already in the csc driver
#if 0
NTSTATUS
MRxProxyBuildInnerIoAsyncWrite (
    IN PRX_CONTEXT RxContext,
    IN PBYTE Buffer,
    IN ULONG WriteByteCount,
    IN PLARGE_INTEGER FileOffset,
    IN OUT PIRP *CalldownIrp
    )

/*++

Routine Description:

    This routine fills in the calldown irp for a proxy read

Arguments:

    RxContext,
    PBYTE Buffer - the write buffer
    ULONG Count  - amount of data to written
    PLARGE_INTEGER FileOffset - fileoffset where the write begins
    PIRP *CallDownIrp - where the Irp is to be stored

Return Value:

    NTSTATUS - Returns the status for the write

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    RxCaptureFcb; RxCaptureFobx;
    PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;

    PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
    PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen);

    RxDbgTrace(+1, Dbg, ("MRxProxyInnerIoWrite.... ByteCount = %08lx, ByteOffset = %08lx %08lx\n",
                            LowIoContext->ParamsFor.ReadWrite.ByteCount,
                            FileOffset->LowPart, FileOffset->HighPart));

    RxLog(("MRxProxyInnerIoWrite %lx %lx %lx",
                            SrvOpen,
                            LowIoContext->ParamsFor.ReadWrite.ByteCount,
                            FileOffset->LowPart));


    RxDbgTrace ( 0, Dbg, ( "MRxProxyInnerIoWrite....  ->Buffer = %8lx\n", Buffer));

    *CalldownIrp = MRxProxyBuildAsynchronousReadWriteRequest(
                        RxContext,                             // IN PVOID Context
                        MRxProxyAsyncEngineCalldownIrpCompletion        // IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
                        );

    if (!*CalldownIrp){
        Status = (STATUS_INSUFFICIENT_RESOURCES);
    }

    RxDbgTrace(-1, Dbg, ("MRxProxyInnerIoWrite.... exit\n"));

    return(Status);
}


//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
//
//  The local debug trace level
//

#undef  Dbg
#define Dbg                              (DEBUG_TRACE_LOCKCTRL)


PIRP
MRxBuildLockRequest (
    IN PIRP irp OPTIONAL,
    IN PFILE_OBJECT fileObject,
    IN PETHREAD UsersThread,
    IN UCHAR MinorCode,
    IN RXVBO ByteOffset,
    IN PLARGE_INTEGER Length,
    IN ULONG Key,
    IN UCHAR Flags,
    IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
    IN PVOID Context OPTIONAL
    )

/*++

Routine Description:

    This function builds an I/O request packet for a lock request.

Arguments:

    Irp - Supplies a pointer to an IRP; allocates one if one is not provided.

    FileObject - Supplies a pointer the file object to which this
        request is directed.  This pointer is copied into the IRP, so
        that the called driver can find its file-based context.  NOTE
        THAT THIS IS NOT A REFERENCED POINTER.  The caller must ensure
        that the file object is not deleted while the I/O operation is
        in progress.  The proxy minirdr accomplishes this by holding a pointer
        (a REFERENCED ptr) to the fileobject in its srvopen while the fileobject is
        open.

    Context - Supplies a PVOID value that is passed to the completion
        routine.

    StartingBlock - the block number of the beginning of the locked
        range.

    ByteOffset - the offset within block of the beginning of the locked
        range.

    Length - the length of the locked range.

    Key - the key value to be associated with the lock.

Return Value:

    None.

--*/

{
    PDEVICE_OBJECT deviceObject;
    PIO_STACK_LOCATION irpSp;

    PAGED_CODE( );

    deviceObject = IoGetRelatedDeviceObject( fileObject );

    //
    // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    // The allocation is performed with an exception handler in case the
    // caller does not have enough quota to allocate the packet.

    if (irp) {
        ASSERT( irp->StackCount >= deviceObject->StackSize );
    } else {
        irp = IoAllocateIrp( deviceObject->StackSize, TRUE );  //joejoe should i charge quota??
    }

    if (!irp) {

        //
        // An IRP could not be allocated.

        return NULL;
    }

    // we have to make sure that the thread that takes the lock is the same as the one that reads
    irp->Tail.Overlay.Thread = UsersThread;
    irp->RequestorMode = KernelMode;

    //
    // Get a pointer to the stack location for the first driver.  This will be
    // used to pass the original function codes and parameters.
    //

    irpSp = IoGetNextIrpStackLocation( irp );

    {   BOOLEAN EnableCalls = CompletionRoutine!=NULL;

        IoSetCompletionRoutine(irp, CompletionRoutine, Context,
                                EnableCalls,EnableCalls,EnableCalls);
    }



    irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL;
    irpSp->MinorFunction = MinorCode;
    irpSp->FileObject = fileObject;   //ok4->FileObj
    irpSp->DeviceObject = deviceObject;

    irpSp->Flags = Flags;

    irpSp->Parameters.LockControl.Length = Length;
    irpSp->Parameters.LockControl.Key = Key;
    irpSp->Parameters.LockControl.ByteOffset.QuadPart = ByteOffset;

    return irp;

}

NTSTATUS
MRxProxyCalldownLockCompletion (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP CalldownIrp,
    IN PVOID Context
    )

/*++

Routine Description:

    This is the I/O completion routine for calldown lock requests. we just call the lowio completion
    and exit

Arguments:

    DeviceObject - Pointer to target device object for the request.

    CalldownIrp - Pointer to I/O request packet used to call down to the underlying filesystem

    Context - Irpcontext of the original request to the rdbss

Return Value:

    NTSTATUS - (STATUS_MORE_PROCESSING_REQUIRED) is returned.


--*/

{
    PRX_CONTEXT RxContext = Context;

    RxDbgTrace ( 0, Dbg, ("MRxProxyCalldownLockCompletion           = %08lx\n", 0));
    //DbgBreakPoint();
    if (CalldownIrp->PendingReturned){
        RxContext->CurrentIrp->IoStatus = CalldownIrp->IoStatus;
        RxContext->StoredStatus = CalldownIrp->IoStatus.Status;
    }
    RxLowIoCompletion(RxContext);

    IoFreeIrp(CalldownIrp);
    return((STATUS_MORE_PROCESSING_REQUIRED));
}


NTSTATUS
MRxProxyLocks (
    IN PRX_CONTEXT RxContext
    )

/*++

Routine Description:

    This routine implements proxy read call. we fill in the info and stuff here BUT we
    do not complete the Irp.

Arguments:

Return Value:

    NTSTATUS - Returns the status for the read

--*/

{
    NTSTATUS Status;
    RxCaptureRequestPacket;
    PIRP CalldownIrp;
    RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
    PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;

    PSRV_OPEN SrvOpen = capFobx->SrvOpen;
    PMRX_LOCAL_SRV_OPEN proxySrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;

    BOOLEAN Wait = FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT)!=0;
    PLARGE_INTEGER LengthAsLI = (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.Length;
    PLARGE_INTEGER OffsetAsLI = (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.ByteOffset;

    char *whichop;

    switch (LowIoContext->Operation) {
    case LOWIO_OP_SHAREDLOCK:     whichop = "SHAREDLOCK"; break;
    case LOWIO_OP_EXCLUSIVELOCK:  whichop = "EXCLUSIVELOCK"; break;
    case LOWIO_OP_UNLOCK:         whichop = "UNLOCK"; break;
    case LOWIO_OP_UNLOCKALL:      whichop = "UNLOCKALL"; break;
    case LOWIO_OP_UNLOCKALLBYKEY:  whichop = "UNLOCKALLBYKEY"; break;
    }

    RxDbgTrace (+1, Dbg, ("MRxExclusiveLock...%s, Flags = %08lx, Key = %08lx\n", whichop,
              LowIoContext->ParamsFor.Locks.Flags,
              LowIoContext->ParamsFor.Locks.Key));
    RxDbgTrace( 0, Dbg, ("  ->Length     = %08lx %08lx\n",
              LengthAsLI->LowPart,
              LengthAsLI->HighPart));
    RxDbgTrace( 0, Dbg, ("  ->ByteOffset    = %08lx %08lx\n",
              OffsetAsLI->LowPart,
              OffsetAsLI->HighPart));
    RxLog(('kLz',3,SrvOpen, LengthAsLI->LowPart, OffsetAsLI->LowPart));

    ASSERT (proxySrvOpen->UnderlyingFileObject);

    CalldownIrp =  MRxBuildLockRequest (
                        NULL                                    ,//IN PIRP irp OPTIONAL,
                        proxySrvOpen->UnderlyingFileObject      ,//IN PFILE_OBJECT fileObject,
                        capReqPacket->Tail.Overlay.Thread                ,//IN PTHREAD UsersThread,
                        capPARAMS->MinorFunction                    ,//IN UCHAR MinorCode,
                        LowIoContext->ParamsFor.Locks.ByteOffset,//IN RXVBO ByteOffset,
                        LengthAsLI                              ,//IN PLARGE_INTEGER Length,
                        LowIoContext->ParamsFor.Locks.Key       ,//IN ULONG Key,
                        (UCHAR)LowIoContext->ParamsFor.Locks.Flags     ,//IN UCHAR Flags,
                        MRxProxyCalldownLockCompletion          ,//IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
                        RxContext                               //IN PVOID Context OPTIONAL
                        );


    if (!CalldownIrp){
        Status = RxContext->StoredStatus = (STATUS_INSUFFICIENT_RESOURCES);
        return(Status);
    }

    Status = RxContext->StoredStatus =
           IoCallDriver(
                 proxySrvOpen->UnderlyingDeviceObject,
                 CalldownIrp
                 );

    if (Status != (STATUS_PENDING)) {
        //copy up the status
        capReqPacket->IoStatus = CalldownIrp->IoStatus;
    }

    RxDbgTrace ( 0, Dbg, (" ---->Initial Status           = %08lx\n", Status));
    RxDbgTrace(-1, Dbg, (" ------> Initial Block status/Info    = %08lx %08lx\n",
                                    capReqPacket->IoStatus.Status, capReqPacket->IoStatus.Information));

    return(Status);
}


NTSTATUS
MRxProxyAssertLockCompletion (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP CalldownIrp,
    IN PVOID Context
    )

/*++

Routine Description:

    This is the I/O completion routine for calldown ios like querydirectory. the rub is that we
    turned synchronous opens into async opens. what we do here is set an event (in the case of a pended
    packet for a sync that we turned async) OR copyup the status;complete;free in the case of a call
    that was always async.

Arguments:

    DeviceObject - Pointer to target device object for the request.

    CalldownIrp - Pointer to I/O request packet used to call down to the underlying filesystem

    Context - Irpcontext of the original request to the rdbss

Return Value:

    NTSTATUS - If (STATUS_MORE_PROCESSING_REQUIRED) is returned.


--*/

{
    PKEVENT Event = Context;

    RxDbgTrace ( 0, Dbg, ("  MRxProxyAssertLockCompletion           = %08lx\n", 0));

    if (CalldownIrp->PendingReturned){
        KeSetEvent( Event, 0, FALSE );
    }

    return((STATUS_MORE_PROCESSING_REQUIRED));
}


NTSTATUS
MRxProxyAssertBufferedFileLocks (
    IN PSRV_OPEN SrvOpen
    )

/*++

Routine Description:

    This routine is called to assert all buffered file locks on a srvopen.


Arguments:

    SrvOpen - Supplies the file whose locks are to be asserted.


Return Value:

    NTSTATUS - Status of operation.


--*/

{
    NTSTATUS Status;
    PFILE_LOCK_INFO FileLock;
    PFCB Fcb = SrvOpen->Fcb;

    PIRP CalldownIrp = NULL;

    PMRX_LOCAL_SRV_OPEN proxySrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;

    UCHAR Flags;
    BOOLEAN Wait = TRUE;

    PKEVENT Event;

    PAGED_CODE();

    RxDbgTrace (+1, Dbg, ("MRxProxyAssertBufferedFileLocks SrvOpen = %08lx", SrvOpen));
    ASSERT (proxySrvOpen->UnderlyingFileObject);

    Event = RxAllocatePoolWithTag( NonPagedPool, sizeof(KEVENT), 'LAxR' );
    if (!CalldownIrp){
        Status = (STATUS_INSUFFICIENT_RESOURCES);
        return(Status);
    }

    try {
        for (FileLock = FsRtlGetNextFileLock(&Fcb->Specific.Fcb.FileLock, TRUE);
                  FileLock != NULL;
                        FileLock = FsRtlGetNextFileLock(&Fcb->Specific.Fcb.FileLock, FALSE)) {

            RxDbgTrace (0, Dbg, ("MRxProxyAssertBufferedFileLocks Exclusive = %08lx, Key = %08lx\n",
                      FileLock->ExclusiveLock,
                      FileLock->Key));
            RxDbgTrace( 0, Dbg, ("  ->Length     = %08lx %08lx\n",
                      FileLock->Length.LowPart,
                      FileLock->Length.HighPart));
            RxDbgTrace( 0, Dbg, ("  ->ByteOffset    = %08lx %08lx\n",
                      FileLock->StartingByte.LowPart,
                      FileLock->StartingByte.HighPart));

            if (FileLock->ExclusiveLock) {
                Flags = SL_EXCLUSIVE_LOCK | SL_FAIL_IMMEDIATELY;
            } else {
                Flags = SL_FAIL_IMMEDIATELY;
            }

            //joejoe we should reuse the irp.........
            CalldownIrp =  MRxBuildLockRequest (
                                NULL                                ,//IN PIRP irp OPTIONAL,
                                proxySrvOpen->UnderlyingFileObject  ,//IN PFILE_OBJECT fileObject,
                                proxySrvOpen->OriginalThread        ,//IN PTHREAD UsersThread,
                                IRP_MN_LOCK                         ,//IN UCHAR MinorCode,
                                FileLock->StartingByte.QuadPart     ,//IN RXVBO ByteOffset,
                                &FileLock->Length                   ,//IN PLARGE_INTEGER Length,
                                FileLock->Key                       ,//IN ULONG Key,
                                Flags                               ,//IN UCHAR Flags,
                                MRxProxyAssertLockCompletion        ,//IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
                                &Event                                //IN PVOID Context OPTIONAL
                                );

            if (!CalldownIrp){
                Status = (STATUS_INSUFFICIENT_RESOURCES);
                try_return(Status);
            }

            CalldownIrp->Flags |= IRP_SYNCHRONOUS_API;

            KeInitializeEvent( Event, SynchronizationEvent, FALSE );

            Status = IoCallDriver(
                         proxySrvOpen->UnderlyingDeviceObject,
                         CalldownIrp
                         );

            if (Status == (STATUS_PENDING)) {
                KeWaitForSingleObject(Event, UserRequest, KernelMode, FALSE, NULL);
                Status = CalldownIrp->IoStatus.Status;
            }

            RxDbgTrace ( 0, Dbg, (" ---->PerLock Status           = %08lx\n", Status));

        }

   try_exit:
        NOTHING;

    } finally {

        ExFreePool(Event);
        if (CalldownIrp) {
            IoFreeIrp(CalldownIrp);
        }
    }

    RxDbgTrace (-1, Dbg, ("--------->Final Status           = %08lx\n", Status));
    return Status;

}

#endif

