понедельник, 9 мая 2011 г.

NOTE: Performance Communication driver with single process

NOTE: Performance Communication driver with single process

Description idea about perfom communication driver.
Dispatching 3 routines:
  1.     IRP_MJ_CREATE
  2.     IRP_MJ_READ
  3.     IRP_MJ_WRITE

Dispatcher IRP_MJ_CREATE
Как косвенный признак начало работы с драйвером для передачи данных. В этом месте можно размести логику запросов на получения данных к нежестоящему драйверу. Основная задача, сформированть Н запросов и отослать нижестоящему драйверу. При завершении запроса положить в список завершенных, если не было запросов от IRP_MJ_READ, если они были то взять первый запрос и скопировать в него тело и установить запрос как завершенный

Dispatcher IRP_MJ_READ

Проверить список завершенных запросов, если не пуст, скопировать тело и установить что запрос завершен, в противном случае, отложить запрос(Mark) не устонавливая Complete.
Сложен в реализации.

Dispatcher IRP_MJ_WRITE
Формируем запрос на отправку данных, копируем из пришедшего запроса "тело". Устанавливаем пришедший запрос как завершонный. А новый запрос отправляем.
Побочный эфект может: Если отправка не удалась, то участник который отослал не узнает об этом. Так что нужно будет ему сообщить либым другим способом.


//-----------------------------------------------------------

typedef struct _PatternReadRequest
{
    LIST_ENTRY        List;
    PIRP              pIrp;
    PVOID             pBuffer;
    struct _DEV_EXT * pDevExt;
} PatternReadRequest,
* PPatternReadRequest;

//-----------------------------------------------------------

NTSTATUS
IzVPipeDispatchCreate(
    IN PDEVICE_OBJECT pDeviceObject,
    IN PIRP pIrp
    )
/*++
** Dispatch IRP_MJ_CREATE
**  Call next driver
**  If succes pass read N requests to next driver
--*/
{
    NTSTATUS Status;
    //Can check Pnp State, write log, PAGED_CODE() and etc.
    IoSkipCurrentIrpStackLocation( pIrp );
    Status = IoCallDriver(pDevExt->UnderlyingPDO, pIrp);
    PassReadRequests( pDevExt );
    return( Status );
}

//-----------------------------------------------------------

void
PassReadRequests(
    PDEV_EXT            pDevExt
    )
/*++
** Building MAX_COUNT_RECV_REQUEST read request and pass down
** Adding to list pending read requests
--*/
{
    PPatternReadRequest pPatternRequest;
    //Validate the once pass read requests
    for ( i = 0; i < MAX_COUNT_RECV_REQUEST; ++i )  {
        pPatternRequest = BuildPatternRequest( pDevExt );
        IoSetCompletionRoutine(
            pPatternRequest->pIrp,
            ReadComplete,
            pPatternRequest,
            TRUE,
            TRUE,
            TRUE
            );

        //Adding to wait list
        KeAcquireSpinLock( &pDevExt->lockRecv, &oldIrql);
        InsertTailList( &pDevExt->ReadRequestWait,                      &pPatternRequest->List );
        KeReleaseSpinLock( &pDevExt->lockRecv, oldIrql );

        //delay request
        Status = IoCallDriver(
            pDevExt->NextLowerDriver,
            pPatternRequest->pIrp
            );
        //Validate Status with PENDING
    }
}

//-----------------------------------------------------------

PPatternReadRequest
IzVPipeBuildPatternRequest(
    PDEV_EXT pDevExt
    )
/*++
** Build patter internal read request
--*/
{
    LARGE_INTEGER       Offset;
    PPatternReadRequest patternRequest;

    patternRequest = ExAllocatePoolWithTag(
        NonPagedPool,
            sizeof( PatternReadRequest ),
            0
            );

    if ( patternRequest == NULL )  {
        goto exit_error;
    }

    patternRequest->pBuffer = ExAllocatePoolWithTag(
            NonPagedPool,
            pDevExt->MaxReceivePacketSize,
            0
            );

    if ( patternRequest->pBuffer == NULL ) {
        ExFreePool(patternRequest);
        goto exit_error;
    }

    Offset.QuadPart = 0;
    patternRequest->pIrp = IoBuildAsynchronousFsdRequest(
            IRP_MJ_READ,
            pDevExt->NextLowerDriver,
            patternRequest->pBuffer,
            pDevExt->MaxReceivePacketSize,
            &Offset,
            NULL
            );

    //Validate patternRequest->pIrp
    patternRequest->pDevExt = pDevExt;
    return (patternRequest);

exit_error:
    //this is fail situation
    return (NULL) ;
}
//-----------------------------------------------------------
NTSTATUS
DispatchRead(
    IN PDEVICE_OBJECT pDeviceObject,
    IN PIRP           pIrp
    )
/*++
** Dispatch IRP_MJ_READ
**
*/
{
    NTSTATUS  Status  = STATUS_SUCCESS;
    ULONG               DataLength;
    KIRQL               oldIrql;
    PPatternReadRequest pPatternRequest;
    PVOID               pIrpBuffer;
    ULONG               i;

    PDEV_EXT  pDevExt = ( PDEV_EXT )pDeviceObject->DeviceExtension;
    PIO_STACK_LOCATION  pIrpStack;

    pIrpStack = IoGetCurrentIrpStackLocation( pIrp );

    DataLength = pIrpStack->Parameters.Read.Length;

    //Validate DataLength

    pIrpBuffer = MmGetSystemAddressForMdlSafe(
        pIrp->MdlAddress,
        NormalPagePriority
        );

    if ( pIrpBuffer == NULL ) {

        Status = STATUS_INVALID_PARAMETER;
        pIrp->IoStatus.Status = Status;

        IoCompleteRequest(
            pIrp,
            IO_NO_INCREMENT
            );

        return ( Status );
    }

    KeAcquireSpinLock(
        &pDevExt->lockRecv, 
        &oldIrql
        );
   
    if ( IsListEmpty ( &pDevExt->ReadRequestComplete ) ) {

    pPatternRequest = (PPatternReadRequest)
        ExAllocatePoolWithTag(
            NonPagedPool,
            sizeof( PatternReadRequest ),
            0
            );

        if ( pPatternRequest == NULL ) {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            pIrp->IoStatus.Status = Status;

            IoCompleteRequest(
                pIrp,
                IO_NO_INCREMENT
                );

            return ( Status );
        }

        pPatternRequest->pIrp = pIrp;

        // insert to list pending request
        InsertTailList(
            &pDevExt->ReadRequestPending,
            &pPatternRequest->List
            );

        IoMarkIrpPending( pPatternRequest->pIrp );

        KeReleaseSpinLock(
            &pDevExt->lockRecv, 
            oldIrql
            );

        return ( STATUS_PENDING );
    }
    else {
          pPatternRequest = (PPatternReadRequest)
            RemoveHeadList( &pDevExt->ReadRequestComplete );

        KeReleaseSpinLock(
            &pDevExt->lockRecv, 
            oldIrql
            );

        if ( pPatternRequest ) {

            RtlCopyMemory(
                pIrpBuffer,
                pPatternRequest->pBuffer,
                pPatternRequest->pIrp->IoStatus.Information
                );

            pIrp->IoStatus.Status = pPatternRequest->pIrp->IoStatus.Status;
            pIrp->IoStatus.Information = pPatternRequest->pIrp->IoStatus.Information;

            IoCompleteRequest(
                pIrp,
                IO_NO_INCREMENT
                );

            pPatternRequest = IzVPipeReusePatternRequest(pDevExt, pPatternRequest);
            //check pPatternRequest
           
            pPatternRequest->pDevExt = pDevExt;

            IoSetCompletionRoutine(
                pPatternRequest->pIrp,
                IzVPipeReadComplete,
                pPatternRequest,
                TRUE,
                TRUE,
                TRUE
                );

            KeAcquireSpinLock( &pDevExt->lockRecv, 
                &oldIrql  );
            InsertTailList( &pDevExt->ReadRequestWait, &pPatternRequest->List );
            KeReleaseSpinLock( &pDevExt->lockRecv, oldIrql );

            Status = IoCallDriver(
                pDevExt->NextLowerDriver,
                pPatternRequest->pIrp
                );

            //Validate Status with STATUS_PENDING

            return ( STATUS_SUCCESS );
        }
    }

    return ( STATUS_PENDING );
}

//-----------------------------------------------------------

PPatternReadRequest
IzVPipeReusePatternRequest(
    PDEV_EXT            pDevExt,
    PPatternReadRequest patternRequest
    )
/*++
** Free old IRP and memory and build new Async read request
--*/
{
    PMDL          mdl;
    PMDL          nextMdl;
    LARGE_INTEGER Offset;

    if ( patternRequest->pIrp->MdlAddress != NULL) {

        for ( mdl = patternRequest->pIrp->MdlAddress; mdl !=             NULL; mdl = nextMdl ) {

            nextMdl = mdl->Next;
            MmUnlockPages( mdl ); 
        }

        patternRequest->pIrp->MdlAddress = NULL;
    }
   
    IoFreeIrp ( patternRequest->pIrp );

    Offset.QuadPart = 0;
    patternRequest->pIrp = IoBuildAsynchronousFsdRequest(
            IRP_MJ_READ,
            pDevExt->NextLowerDriver,
            patternRequest->pBuffer,
            pDevExt->MaxReceivePacketSize,
            &Offset,
            NULL
            );

    // Check patternRequest->pIrp

    return (patternRequest);

exit_error:
    //this is fail situation
    return ( NULL );
}

//-----------------------------------------------------------

void
IzVPipeFreePatternRequest(
    PPatternReadRequest patternRequest
    )
/*++
** Free intern pattern read request
--*/
{
    PMDL mdl;
    PMDL nextMdl;

    if ( patternRequest->pIrp->MdlAddress != NULL) {

        for ( mdl = patternRequest->pIrp->MdlAddress; mdl !=                 NULL; mdl = nextMdl ) {

            nextMdl = mdl->Next;
            MmUnlockPages( mdl );
            IoFreeMdl( mdl ); 
        }

        patternRequest->pIrp->MdlAddress = NULL;
    }
   
    IoFreeIrp ( patternRequest->pIrp );
    ExFreePoolWithTag( patternRequest, 0 );
}

//-----------------------------------------------------------

NTSTATUS
IzVPipeWriteComplete(
    IN PDEVICE_OBJECT pDeviceObject,
    IN PIRP           pIrp,
    PVOID             pUncastedContext // pBufferWorker
    )
/*++
    Stub write complete with free request
--*/
{

    ExFreePool( pUncastedContext );
    //IoFreeIrp ( pIrp );

    return ( STATUS_MORE_PROCESSING_REQUIRED );
}

//-----------------------------------------------------------

NTSTATUS
IzVPipeDispatchWrite(
    IN PDEVICE_OBJECT pDeviceObject,
    IN PIRP           pIrp
    )
/*++
** Dispatch IRP_MJ_WRITE
**  Allocate Async request
**  Copy request from Dispatch to new Async request
** SetComplete as Success.
** pass Async request to next driver
*/
{
    NTSTATUS           Status = STATUS_SUCCESS;
    PDEV_EXT           pDevExt = ( PDEV_EXT )pDeviceObject->DeviceExtension;
    PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
    ULONG              DataLength;

    PIRP               pIrpWorker;
    PVOID              pBufferWorker;
    PVOID              pIrpBuffer;

    //Validate Pnp, increment device usage

    DataLength = pIrpStack->Parameters.Write.Length;

    pIrpBuffer = MmGetSystemAddressForMdlSafe(
        pIrp->MdlAddress,
        NormalPagePriority
        );

    if ( pIrpBuffer == NULL ) {

        Status = STATUS_INVALID_PARAMETER;
        pIrp->IoStatus.Status = Status;

        IoCompleteRequest(
            pIrp,
            IO_NO_INCREMENT
            );

        return ( Status );
    }

    pBufferWorker = ExAllocatePoolWithTag(
        NonPagedPool,
        DataLength,
        0
        );

    //Check pBufferWorker

    //copy memory from request to new async request buffer
    RtlCopyMemory(
        pBufferWorker,
        pIrpBuffer, //pIrp->AssociatedIrp.SystemBuffer,
        DataLength
        );
    // Buildig write request
    pIrpWorker = IoBuildAsynchronousFsdRequest(
            IRP_MJ_WRITE,
            pDevExt->NextLowerDriver,
            pBufferWorker,
            DataLength,
            NULL,
            NULL
            );

    //Check pIrpWorker

    pIrp->IoStatus.Status = Status = STATUS_SUCCESS;
    //set request success, but this is request not be completeed
    IoCompleteRequest(
        pIrp,
        IO_NO_INCREMENT
        );

    IoSetCompletionRoutine(
        pIrpWorker,
        IzVPipeWriteComplete,
        pBufferWorker,
        TRUE,
        TRUE,
        TRUE
        );

    Status = IoCallDriver(
        pDevExt->NextLowerDriver,
        pIrpWorker
        );
    if ( Status != STATUS_PENDING ) {

    }
   
    return ( Status );
}

Комментариев нет:

Отправить комментарий