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