[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH 10/14] Implement ring protocol
From: Owen Smith <owen.smith@xxxxxxxxxx> * Uses a IO_CSQ for read and write IRPs Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx> --- src/xencons/frontend.c | 33 +--- src/xencons/frontend.h | 21 +- src/xencons/pdo.c | 11 +- src/xencons/ring.c | 519 ++++++++++++++++++++++++++++++++++++++++++++++++- src/xencons/ring.h | 18 ++ 5 files changed, 554 insertions(+), 48 deletions(-) diff --git a/src/xencons/frontend.c b/src/xencons/frontend.c index fa7443d..e914985 100755 --- a/src/xencons/frontend.c +++ b/src/xencons/frontend.c @@ -223,37 +223,20 @@ FrontendGetProtocol( return Frontend->Protocol; } -NTSTATUS -FrontendDispatchCreate( - IN PXENCONS_FRONTEND Frontend, - IN PFILE_OBJECT FileObject - ) -{ - UNREFERENCED_PARAMETER(Frontend); - UNREFERENCED_PARAMETER(FileObject); - return STATUS_SUCCESS; -} - -NTSTATUS -FrontendDispatchCleanup( - IN PXENCONS_FRONTEND Frontend, - IN PFILE_OBJECT FileObject +static FORCEINLINE PXENCONS_RING +__FrontendGetRing( + IN PXENCONS_FRONTEND Frontend ) { - UNREFERENCED_PARAMETER(Frontend); - UNREFERENCED_PARAMETER(FileObject); - return STATUS_SUCCESS; + return Frontend->Ring; } -NTSTATUS -FrontendDispatchReadWrite( - IN PXENCONS_FRONTEND Frontend, - IN PIRP Irp +PXENCONS_RING +FrontendGetRing( + IN PXENCONS_FRONTEND Frontend ) { - UNREFERENCED_PARAMETER(Frontend); - UNREFERENCED_PARAMETER(Irp); - return STATUS_DEVICE_NOT_READY; + return __FrontendGetRing(Frontend); } static VOID diff --git a/src/xencons/frontend.h b/src/xencons/frontend.h index 5eff067..b7177d0 100755 --- a/src/xencons/frontend.h +++ b/src/xencons/frontend.h @@ -38,6 +38,8 @@ typedef struct _XENCONS_FRONTEND XENCONS_FRONTEND, *PXENCONS_FRONTEND; +#include "ring.h" + typedef enum _FRONTEND_STATE { FRONTEND_UNKNOWN, FRONTEND_CLOSED, @@ -103,22 +105,9 @@ FrontendGetProtocol( IN PXENCONS_FRONTEND Frontend ); -extern NTSTATUS -FrontendDispatchCreate( - IN PXENCONS_FRONTEND Frontend, - IN PFILE_OBJECT FileObject - ); - -extern NTSTATUS -FrontendDispatchCleanup( - IN PXENCONS_FRONTEND Frontend, - IN PFILE_OBJECT FileObject - ); - -extern NTSTATUS -FrontendDispatchReadWrite( - IN PXENCONS_FRONTEND Frontend, - IN PIRP Irp +extern PXENCONS_RING +FrontendGetRing( + IN PXENCONS_FRONTEND Frontend ); #endif // _XENCONS_FRONTEND_H diff --git a/src/xencons/pdo.c b/src/xencons/pdo.c index 528d36e..e02313b 100755 --- a/src/xencons/pdo.c +++ b/src/xencons/pdo.c @@ -44,6 +44,7 @@ #include "driver.h" #include "registry.h" #include "frontend.h" +#include "ring.h" #include "thread.h" #include "dbg_print.h" #include "assert.h" @@ -1609,8 +1610,8 @@ PdoDispatchCreate( StackLocation = IoGetCurrentIrpStackLocation(Irp); - status = FrontendDispatchCreate(Pdo->Frontend, - StackLocation->FileObject); + status = RingDispatchCreate(FrontendGetRing(Pdo->Frontend), + StackLocation->FileObject); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); @@ -1629,8 +1630,8 @@ PdoDispatchCleanup( StackLocation = IoGetCurrentIrpStackLocation(Irp); - status = FrontendDispatchCleanup(Pdo->Frontend, - StackLocation->FileObject); + status = RingDispatchCleanup(FrontendGetRing(Pdo->Frontend), + StackLocation->FileObject); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); @@ -1666,7 +1667,7 @@ PdoDispatchReadWrite( IoMarkIrpPending(Irp); - status = FrontendDispatchReadWrite(Pdo->Frontend, Irp); + status = RingDispatchReadWrite(FrontendGetRing(Pdo->Frontend), Irp); if (!NT_SUCCESS(status)) goto fail1; diff --git a/src/xencons/ring.c b/src/xencons/ring.c index 321f4e9..83e1761 100755 --- a/src/xencons/ring.c +++ b/src/xencons/ring.c @@ -41,10 +41,17 @@ #include "frontend.h" #include "ring.h" +#include "names.h" #include "dbg_print.h" #include "assert.h" #include "util.h" +typedef struct _XENCONS_CSQ { + IO_CSQ Csq; + LIST_ENTRY List; + KSPIN_LOCK Lock; +} XENCONS_CSQ, *PXENCONS_CSQ; + struct _XENCONS_RING { PXENCONS_FRONTEND Frontend; KSPIN_LOCK Lock; @@ -63,6 +70,8 @@ struct _XENCONS_RING { XENBUS_DEBUG_INTERFACE DebugInterface; PXENBUS_DEBUG_CALLBACK DebugCallback; PXENBUS_GNTTAB_CACHE GnttabCache; + XENCONS_CSQ Read; + XENCONS_CSQ Write; }; #define RING_TAG 'GNIR' @@ -104,15 +113,472 @@ RingReleaseLock( KeReleaseSpinLockFromDpcLevel(&Ring->Lock); } +IO_CSQ_INSERT_IRP_EX RingCsqInsertIrpEx; + +NTSTATUS +RingCsqInsertIrpEx( + IN PIO_CSQ Csq, + IN PIRP Irp, + IN PVOID InsertContext OPTIONAL + ) +{ + BOOLEAN ReInsert = (BOOLEAN)(ULONG_PTR)InsertContext; + PXENCONS_CSQ Queue; + + Queue = CONTAINING_RECORD(Csq, XENCONS_CSQ, Csq); + + if (ReInsert) { + // This only occurs if the worker thread de-queued the IRP but + // then found the console to be blocked. + InsertHeadList(&Queue->List, &Irp->Tail.Overlay.ListEntry); + } else { + InsertTailList(&Queue->List, &Irp->Tail.Overlay.ListEntry); + } + + return STATUS_SUCCESS; +} + +IO_CSQ_REMOVE_IRP RingCsqRemoveIrp; + +VOID +RingCsqRemoveIrp( + IN PIO_CSQ Csq, + IN PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(Csq); + + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +} + +IO_CSQ_PEEK_NEXT_IRP RingCsqPeekNextIrp; + +PIRP +RingCsqPeekNextIrp( + IN PIO_CSQ Csq, + IN PIRP Irp, + IN PVOID PeekContext OPTIONAL + ) +{ + PXENCONS_CSQ Queue; + PLIST_ENTRY ListEntry; + PIRP NextIrp; + + Queue = CONTAINING_RECORD(Csq, XENCONS_CSQ, Csq); + + ListEntry = (Irp == NULL) ? + Queue->List.Flink : + Irp->Tail.Overlay.ListEntry.Flink; + + if (ListEntry == &Queue->List) + return NULL; + + NextIrp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry); + if (PeekContext == NULL) + return NextIrp; + + for (;;) { + PIO_STACK_LOCATION StackLocation; + + if (ListEntry == &Queue->List) + return NULL; + + StackLocation = IoGetCurrentIrpStackLocation(NextIrp); + + if (StackLocation->FileObject == PeekContext) + return NextIrp; + + ListEntry = ListEntry->Flink; + NextIrp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry); + } + // unreachable +} + +#pragma warning(push) +#pragma warning(disable:28167) // function changes IRQL + +IO_CSQ_ACQUIRE_LOCK RingCsqAcquireLock; + +VOID +RingCsqAcquireLock( + IN PIO_CSQ Csq, + OUT PKIRQL Irql + ) +{ + PXENCONS_CSQ Queue; + + Queue = CONTAINING_RECORD(Csq, XENCONS_CSQ, Csq); + + KeAcquireSpinLock(&Queue->Lock, Irql); +} + +IO_CSQ_RELEASE_LOCK RingCsqReleaseLock; + +VOID +RingCsqReleaseLock( + IN PIO_CSQ Csq, + IN KIRQL Irql + ) +{ + PXENCONS_CSQ Queue; + + Queue = CONTAINING_RECORD(Csq, XENCONS_CSQ, Csq); + + KeReleaseSpinLock(&Queue->Lock, Irql); +} + +#pragma warning(pop) + +IO_CSQ_COMPLETE_CANCELED_IRP RingCsqCompleteCanceledIrp; + +VOID +RingCsqCompleteCanceledIrp( + IN PIO_CSQ Csq, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + UCHAR MajorFunction; + + UNREFERENCED_PARAMETER(Csq); + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + MajorFunction = StackLocation->MajorFunction; + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_CANCELLED; + + Trace("CANCELLED (%02x:%s)\n", + MajorFunction, + MajorFunctionName(MajorFunction)); + + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +static FORCEINLINE NTSTATUS +__RingCsqCreate( + IN PXENCONS_CSQ Csq + ) +{ + NTSTATUS status; + + KeInitializeSpinLock(&Csq->Lock); + InitializeListHead(&Csq->List); + + status = IoCsqInitializeEx(&Csq->Csq, + RingCsqInsertIrpEx, + RingCsqRemoveIrp, + RingCsqPeekNextIrp, + RingCsqAcquireLock, + RingCsqReleaseLock, + RingCsqCompleteCanceledIrp); + if (!NT_SUCCESS(status)) + goto fail1; + + return STATUS_SUCCESS; + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +static FORCEINLINE VOID +__RingCsqDestroy( + IN PXENCONS_CSQ Csq + ) +{ + ASSERT(IsListEmpty(&Csq->List)); + + RtlZeroMemory(&Csq->Csq, sizeof(IO_CSQ)); + RtlZeroMemory(&Csq->List, sizeof(LIST_ENTRY)); + RtlZeroMemory(&Csq->Lock, sizeof(KSPIN_LOCK)); +} + +static FORCEINLINE ULONG +__RingCopyFromIn( + IN PXENCONS_RING Ring, + IN PCHAR Data, + IN ULONG Length + ) +{ + struct xencons_interface *Shared; + XENCONS_RING_IDX cons; + XENCONS_RING_IDX prod; + ULONG Offset; + + Shared = Ring->Shared; + + KeMemoryBarrier(); + + cons = Shared->in_cons; + prod = Shared->in_prod; + + KeMemoryBarrier(); + + // is there anything on in ring? + if (prod - cons == 0) + return 0; + + Offset = 0; + while (Length != 0) { + ULONG Available; + ULONG Index; + ULONG CopyLength; + + Available = prod - cons; + + if (Available == 0) + break; + + Index = MASK_XENCONS_IDX(cons, Shared->in); + + CopyLength = __min(Length, Available); + CopyLength = __min(CopyLength, sizeof(Shared->in) - Index); + + RtlCopyMemory(Data + Offset, &Shared->in[Index], CopyLength); + + Offset += CopyLength; + Length -= CopyLength; + cons += CopyLength; + } + + KeMemoryBarrier(); + + Shared->in_cons = cons; + + KeMemoryBarrier(); + + return Offset; +} + +static FORCEINLINE ULONG + __RingCopyToOut( + IN PXENCONS_RING Ring, + IN PCHAR Data, + IN ULONG Length + ) +{ + struct xencons_interface *Shared; + XENCONS_RING_IDX cons; + XENCONS_RING_IDX prod; + ULONG Offset; + + Shared = Ring->Shared; + + KeMemoryBarrier(); + + prod = Shared->out_prod; + cons = Shared->out_cons; + + KeMemoryBarrier(); + + // is there any space on out ring? + if ((cons + sizeof(Shared->out) - prod) == 0) + return 0; + + Offset = 0; + while (Length != 0) { + ULONG Available; + ULONG Index; + ULONG CopyLength; + + Available = cons + sizeof(Shared->out) - prod; + + if (Available == 0) + break; + + Index = MASK_XENCONS_IDX(prod, Shared->out); + + CopyLength = __min(Length, Available); + CopyLength = __min(CopyLength, sizeof(Shared->out) - Index); + + RtlCopyMemory(&Shared->out[Index], Data + Offset, CopyLength); + + Offset += CopyLength; + Length -= CopyLength; + prod += CopyLength; + } + + KeMemoryBarrier(); + + Shared->out_prod = prod; + + KeMemoryBarrier(); + + return Offset; +} + static BOOLEAN RingPoll( IN PXENCONS_RING Ring ) { - UNREFERENCED_PARAMETER(Ring); + PIRP Irp; + PIO_STACK_LOCATION StackLocation; + ULONG Bytes; + ULONG Read; + ULONG Written; + NTSTATUS status; + + Read = 0; + Written = 0; + + for (;;) { + Irp = IoCsqRemoveNextIrp(&Ring->Read.Csq, NULL); + if (Irp == NULL) + break; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + ASSERT(StackLocation->MajorFunction == IRP_MJ_READ); + + Bytes = __RingCopyFromIn(Ring, + Irp->AssociatedIrp.SystemBuffer, + StackLocation->Parameters.Read.Length); + Read += Bytes; + if (Bytes) { + Irp->IoStatus.Information = Bytes; + Irp->IoStatus.Status = STATUS_SUCCESS; + + Trace("COMPLETED (%02x:%s) (%u)\n", + IRP_MJ_READ, + MajorFunctionName(IRP_MJ_READ), + Bytes); + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + continue; + } + + // no data on read ring + status = IoCsqInsertIrpEx(&Ring->Read.Csq, Irp, NULL, (PVOID)TRUE); + ASSERT(NT_SUCCESS(status)); + break; + } + + for (;;) { + Irp = IoCsqRemoveNextIrp(&Ring->Write.Csq, NULL); + if (Irp == NULL) + break; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + ASSERT(StackLocation->MajorFunction == IRP_MJ_WRITE); + + Bytes = __RingCopyToOut(Ring, + Irp->AssociatedIrp.SystemBuffer, + StackLocation->Parameters.Write.Length); + Written += Bytes; + if (Bytes) { + Irp->IoStatus.Information = Bytes; + Irp->IoStatus.Status = STATUS_SUCCESS; + + Trace("COMPLETED (%02x:%s) (%u)\n", + IRP_MJ_WRITE, + MajorFunctionName(IRP_MJ_WRITE), + Bytes); + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + continue; + } + + // no space on write ring + status = IoCsqInsertIrpEx(&Ring->Write.Csq, Irp, NULL, (PVOID)TRUE); + ASSERT(NT_SUCCESS(status)); + break; + } + + if (Read || Written) + XENBUS_EVTCHN(Send, + &Ring->EvtchnInterface, + Ring->Channel); + return FALSE; } +static FORCEINLINE VOID +__RingCancelIrps( + IN PXENCONS_RING Ring, + IN PFILE_OBJECT FileObject + ) +{ + for (;;) { + PIRP Irp; + + Irp = IoCsqRemoveNextIrp(&Ring->Read.Csq, FileObject); + if (Irp == NULL) + break; + + RingCsqCompleteCanceledIrp(&Ring->Read.Csq, Irp); + } + for (;;) { + PIRP Irp; + + Irp = IoCsqRemoveNextIrp(&Ring->Write.Csq, FileObject); + if (Irp == NULL) + break; + + RingCsqCompleteCanceledIrp(&Ring->Write.Csq, Irp); + } +} + +NTSTATUS +RingDispatchCreate( + IN PXENCONS_RING Ring, + IN PFILE_OBJECT FileObject + ) +{ + UNREFERENCED_PARAMETER(Ring); + UNREFERENCED_PARAMETER(FileObject); + + // nothing special for Create + return STATUS_SUCCESS; +} + +NTSTATUS +RingDispatchCleanup( + IN PXENCONS_RING Ring, + IN PFILE_OBJECT FileObject + ) +{ + // Only cancel IRPs for this FileObject + __RingCancelIrps(Ring, FileObject); + return STATUS_SUCCESS; +} + +NTSTATUS +RingDispatchReadWrite( + IN PXENCONS_RING Ring, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + switch (StackLocation->MajorFunction) { + case IRP_MJ_READ: + status = STATUS_INVALID_PARAMETER; + if (StackLocation->Parameters.Read.Length == 0) + break; + status = IoCsqInsertIrpEx(&Ring->Read.Csq, Irp, NULL, (PVOID)FALSE); + break; + + case IRP_MJ_WRITE: + status = STATUS_INVALID_PARAMETER; + if (StackLocation->Parameters.Write.Length == 0) + break; + status = IoCsqInsertIrpEx(&Ring->Write.Csq, Irp, NULL, (PVOID)FALSE); + break; + + default: + status = STATUS_NOT_SUPPORTED; + break; + } + if (NT_SUCCESS(status)) + KeInsertQueueDpc(&Ring->Dpc, NULL, NULL); + + return status; +} + __drv_functionClass(KDEFERRED_ROUTINE) __drv_maxIRQL(DISPATCH_LEVEL) __drv_minIRQL(DISPATCH_LEVEL) @@ -444,7 +910,8 @@ RingDisable( { Trace("=====>\n"); - // empty queue(s) + // cancel all IRPs, regardless of FileObject + __RingCancelIrps(Ring, NULL); ASSERT3U(KeGetCurrentIrql(), == , DISPATCH_LEVEL); @@ -518,6 +985,8 @@ RingCreate( { NTSTATUS status; + Trace("=====>\n"); + *Ring = __RingAllocate(sizeof(XENCONS_RING)); status = STATUS_NO_MEMORY; @@ -542,8 +1011,47 @@ RingCreate( KeInitializeDpc(&(*Ring)->Dpc, RingDpc, *Ring); + status = __RingCsqCreate(&(*Ring)->Read); + if (!NT_SUCCESS(status)) + goto fail2; + + status = __RingCsqCreate(&(*Ring)->Write); + if (!NT_SUCCESS(status)) + goto fail3; + + Trace("<=====\n"); + return STATUS_SUCCESS; +fail3: + Error("fail3\n"); + + __RingCsqDestroy(&(*Ring)->Read); + +fail2: + Error("fail2\n"); + + RtlZeroMemory(&(*Ring)->Dpc, sizeof(KDPC)); + + RtlZeroMemory(&(*Ring)->Lock, sizeof(KSPIN_LOCK)); + + RtlZeroMemory(&(*Ring)->GnttabInterface, + sizeof(XENBUS_GNTTAB_INTERFACE)); + + RtlZeroMemory(&(*Ring)->EvtchnInterface, + sizeof(XENBUS_EVTCHN_INTERFACE)); + + RtlZeroMemory(&(*Ring)->StoreInterface, + sizeof(XENBUS_STORE_INTERFACE)); + + RtlZeroMemory(&(*Ring)->DebugInterface, + sizeof(XENBUS_DEBUG_INTERFACE)); + + (*Ring)->Frontend = NULL; + + ASSERT(IsZeroMemory(*Ring, sizeof(XENCONS_RING))); + __RingFree(*Ring); + fail1: Error("fail1 (%08x)\n", status); @@ -555,6 +1063,11 @@ RingDestroy( IN PXENCONS_RING Ring ) { + Trace("=====>\n"); + + __RingCsqDestroy(&Ring->Write); + __RingCsqDestroy(&Ring->Read); + RtlZeroMemory(&Ring->Dpc, sizeof(KDPC)); RtlZeroMemory(&Ring->Lock, sizeof(KSPIN_LOCK)); @@ -575,4 +1088,6 @@ RingDestroy( ASSERT(IsZeroMemory(Ring, sizeof(XENCONS_RING))); __RingFree(Ring); + + Trace("<=====\n"); } diff --git a/src/xencons/ring.h b/src/xencons/ring.h index e9f549d..194c1a7 100755 --- a/src/xencons/ring.h +++ b/src/xencons/ring.h @@ -75,4 +75,22 @@ RingDisconnect( IN PXENCONS_RING Ring ); +extern NTSTATUS +RingDispatchCreate( + IN PXENCONS_RING Frontend, + IN PFILE_OBJECT FileObject + ); + +extern NTSTATUS +RingDispatchCleanup( + IN PXENCONS_RING Ring, + IN PFILE_OBJECT FileObject + ); + +extern NTSTATUS +RingDispatchReadWrite( + IN PXENCONS_RING Ring, + IN PIRP Irp + ); + #endif // _XENCONS_RING_H -- 2.8.3 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |