[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.