]> xenbits.xensource.com Git - people/pauldu/xenbus.git/commitdiff
Re-worked GNTTAB.
authorPaul Durrant <paul.durrant@citrix.com>
Fri, 11 Apr 2014 10:09:20 +0000 (11:09 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Fri, 11 Apr 2014 14:57:23 +0000 (15:57 +0100)
The new version of the interface no longer exposes raw references to clients.
They are now behind an opaque XENVIF_GNTTAB_DESCRIPTOR, analogous to the
XENVIF_EVTCHN_DESCRIPTOR which hides raw ports from clients.
The allocator is also more sophisticated. It uses a pool with per-cpu
magazines for lockless access backed by rangesets.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
include/gnttab_interface.h
proj/xenbus/xenbus.vcxproj
src/xenbus/gnttab.c
src/xenbus/pool.c [new file with mode: 0644]
src/xenbus/pool.h [new file with mode: 0644]
src/xenbus/range_set.c
src/xenbus/range_set.h

index 65e62e000f4e78a72ae8358949980474105ec069..6b57ce81feece51d563b8c3a9e2ef065c4bfc307 100644 (file)
@@ -37,66 +37,56 @@ typedef enum _XENBUS_GNTTAB_ENTRY_TYPE {
     GNTTAB_ENTRY_FULL_PAGE
 } XENBUS_GNTTAB_ENTRY_TYPE, *PXENBUS_GNTTAB_ENTRY_TYPE;
 
-typedef struct _XENBUS_GNTTAB_COPY_OPERATION {
-    LIST_ENTRY  ListEntry;
-    USHORT      RemoteDomain;
-    ULONG       RemoteReference;
-    ULONG       RemoteOffset;
-    PFN_NUMBER  Pfn;
-    ULONG       Offset;
-    ULONG       Length;
-} XENBUS_GNTTAB_COPY_OPERATION, *PXENBUS_GNTTAB_COPY_OPERATION;
+typedef struct _XENBUS_GNTTAB_DESCRIPTOR    XENBUS_GNTTAB_DESCRIPTOR, *PXENBUS_GNTTAB_DESCRIPTOR;
 
 #define DEFINE_GNTTAB_OPERATIONS                                    \
         GNTTAB_OPERATION(VOID,                                      \
                          Acquire,                                   \
                          (                                          \
-                         IN  PXENBUS_GNTTAB_CONTEXT  Context        \
+                         IN  PXENBUS_GNTTAB_CONTEXT     Context     \
                          )                                          \
                          )                                          \
         GNTTAB_OPERATION(VOID,                                      \
                          Release,                                   \
                          (                                          \
-                         IN  PXENBUS_GNTTAB_CONTEXT  Context        \
+                         IN  PXENBUS_GNTTAB_CONTEXT     Context     \
                          )                                          \
                          )                                          \
-        GNTTAB_OPERATION(NTSTATUS,                                  \
+        GNTTAB_OPERATION(PXENBUS_GNTTAB_DESCRIPTOR,                 \
                          Get,                                       \
                          (                                          \
-                         IN  PXENBUS_GNTTAB_CONTEXT  Context,       \
-                         OUT PULONG                  Reference      \
+                         IN  PXENBUS_GNTTAB_CONTEXT     Context     \
                          )                                          \
                          )                                          \
         GNTTAB_OPERATION(VOID,                                      \
                          Put,                                       \
                          (                                          \
-                         IN  PXENBUS_GNTTAB_CONTEXT  Context,       \
-                         IN  ULONG                   Reference      \
+                         IN  PXENBUS_GNTTAB_CONTEXT     Context,    \
+                         IN  PXENBUS_GNTTAB_DESCRIPTOR  Descriptor  \
                          )                                          \
                          )                                          \
         GNTTAB_OPERATION(NTSTATUS,                                  \
                          PermitForeignAccess,                       \
                          (                                          \
-                         IN  PXENBUS_GNTTAB_CONTEXT   Context,      \
-                         IN  ULONG                    Reference,    \
-                         IN  USHORT                   Domain,       \
-                         IN  XENBUS_GNTTAB_ENTRY_TYPE Type,         \
+                         IN  PXENBUS_GNTTAB_CONTEXT     Context,    \
+                         IN  PXENBUS_GNTTAB_DESCRIPTOR  Descriptor, \
+                         IN  USHORT                     Domain,     \
+                         IN  XENBUS_GNTTAB_ENTRY_TYPE   Type,       \
                          ...                                        \
                          )                                          \
                          )                                          \
         GNTTAB_OPERATION(NTSTATUS,                                  \
                          RevokeForeignAccess,                       \
                          (                                          \
-                         IN  PXENBUS_GNTTAB_CONTEXT  Context,       \
-                         IN  ULONG                   Reference      \
+                         IN  PXENBUS_GNTTAB_CONTEXT     Context,    \
+                         IN  PXENBUS_GNTTAB_DESCRIPTOR  Descriptor  \
                          )                                          \
                          )                                          \
-        GNTTAB_OPERATION(NTSTATUS,                                  \
-                         Copy,                                      \
+        GNTTAB_OPERATION(ULONG,                                     \
+                         Reference,                                 \
                          (                                          \
-                         IN  PXENBUS_GNTTAB_CONTEXT  Context,       \
-                         IN  PLIST_ENTRY             List,          \
-                         IN  ULONG                   Count          \
+                         IN  PXENBUS_GNTTAB_CONTEXT     Context,    \
+                         IN  PXENBUS_GNTTAB_DESCRIPTOR  Descriptor  \
                          )                                          \
                          )
 
@@ -127,7 +117,7 @@ DEFINE_GUID(GUID_GNTTAB_INTERFACE,
             0xd6,
             0xe);
 
-#define GNTTAB_INTERFACE_VERSION    3
+#define GNTTAB_INTERFACE_VERSION    4
 
 #define GNTTAB_OPERATIONS(_Interface) \
         (PXENBUS_GNTTAB_OPERATIONS *)((ULONG_PTR)(_Interface))
index 779d3a22898ec83f546e2f151cf8a0fd54201ff6..f4085be769727a62d94f38a0bb3129bb18a1cf38 100644 (file)
@@ -90,6 +90,7 @@
                <ClCompile Include="..\..\src\xenbus\thread.c" />
                <ClCompile Include="..\..\src\xenbus\range_set.c" />
                <ClCompile Include="..\..\src\xenbus\balloon.c" />
+               <ClCompile Include="..\..\src\xenbus\pool.c" />
        </ItemGroup>
        <ItemGroup>
                <ResourceCompile Include="..\..\src\xenbus\xenbus.rc" />
index 8ae786f609a38e5f7db75b8f45b98d8b610ffd03..1fcf236412407804b6b86450aac81850c2a0fcad 100644 (file)
 
 #include "gnttab.h"
 #include "fdo.h"
+#include "range_set.h"
+#include "pool.h"
 #include "dbg_print.h"
 #include "assert.h"
 
-#define GNTTAB_MAXIMUM_FRAME_COUNT    32
-#define GNTTAB_ENTRY_PER_FRAME              (PAGE_SIZE / sizeof (grant_entry_v1_t))
+#define GNTTAB_MAXIMUM_FRAME_COUNT  32
+#define GNTTAB_ENTRY_PER_FRAME      (PAGE_SIZE / sizeof (grant_entry_v1_t))
 
 // Xen requires that we avoid the first 8 entries of the table and
 // we also reserve 1 entry for the crash kernel
 #define GNTTAB_RESERVED_ENTRY_COUNT 9
 
-#define GNTTAB_INVALID_REFERENCE    0
-
-#define GNTTAB_IS_INVALID_REFERENCE(_Reference) \
-        ((_Reference) < GNTTAB_RESERVED_ENTRY_COUNT)
-
-typedef struct _GNTTAB_DESCRIPTOR {
-    LIST_ENTRY          ListEntry;
-    ULONG               Next;
-    PVOID               Caller;
+struct _XENBUS_GNTTAB_DESCRIPTOR {
+    ULONG               Reference;
     grant_entry_v1_t    Entry;
-} GNTTAB_DESCRIPTOR, *PGNTTAB_DESCRIPTOR;
+};
 
 struct _XENBUS_GNTTAB_CONTEXT {
     LONG                        References;
@@ -65,10 +60,8 @@ struct _XENBUS_GNTTAB_CONTEXT {
     ULONG                       FrameCount;
     grant_entry_v1_t            *Entry;
     KSPIN_LOCK                  Lock;
-    ULONG                       HeadFreeReference;
-    PULONG                      TailFreeReference;
-    GNTTAB_DESCRIPTOR           Descriptor[GNTTAB_MAXIMUM_FRAME_COUNT * GNTTAB_ENTRY_PER_FRAME];
-    LIST_ENTRY                  List;
+    PXENBUS_RANGE_SET           RangeSet;
+    PXENBUS_POOL                DescriptorPool;
     PXENBUS_SUSPEND_INTERFACE   SuspendInterface;
     PXENBUS_SUSPEND_CALLBACK    SuspendCallbackEarly;
     PXENBUS_DEBUG_INTERFACE     DebugInterface;
@@ -93,16 +86,15 @@ __GnttabFree(
     __FreePoolWithTag(Buffer, GNTTAB_TAG);
 }
 
-static NTSTATUS
-GnttabExpand(
+static FORCEINLINE NTSTATUS
+__GnttabExpand(
     IN  PXENBUS_GNTTAB_CONTEXT  Context
     )
 {
     ULONG                       FrameIndex;
     PFN_NUMBER                  Pfn;
-    ULONG                       Start;
-    ULONG                       End;
-    ULONG                       Reference;
+    ULONGLONG                   Start;
+    ULONGLONG                   End;
     NTSTATUS                    status;
 
     FrameIndex = Context->FrameCount;
@@ -124,16 +116,9 @@ GnttabExpand(
     Start = __max(GNTTAB_RESERVED_ENTRY_COUNT, FrameIndex * GNTTAB_ENTRY_PER_FRAME);
     End = (Context->FrameCount * GNTTAB_ENTRY_PER_FRAME) - 1;
 
-    Trace("adding refrences [%08x - %08x]\n", Start, End);
+    Trace("adding refrences [%08llx - %08llx]\n", Start, End);
 
-    for (Reference = Start; Reference <= End; Reference++) {
-        PGNTTAB_DESCRIPTOR  Descriptor = &Context->Descriptor[Reference];
-
-        *Context->TailFreeReference = Reference;
-
-        ASSERT(GNTTAB_IS_INVALID_REFERENCE(Descriptor->Next));
-        Context->TailFreeReference = &Descriptor->Next;
-    }
+    RangeSetPut(Context->RangeSet, Start, End);
 
     return STATUS_SUCCESS;
 
@@ -143,133 +128,180 @@ fail1:
     return status;
 }
 
-static FORCEINLINE VOID
-__GnttabEmpty(
-    IN  PXENBUS_GNTTAB_CONTEXT  Context
+static NTSTATUS
+GnttabDescriptorCtor(
+    IN  PVOID                   Argument,
+    IN  PVOID                   Object
     )
 {
-    while (!GNTTAB_IS_INVALID_REFERENCE(Context->HeadFreeReference)) {
-        ULONG               Reference = Context->HeadFreeReference;
-        PGNTTAB_DESCRIPTOR  Descriptor = &Context->Descriptor[Reference];
+    PXENBUS_GNTTAB_CONTEXT      Context = Argument;
+    PXENBUS_GNTTAB_DESCRIPTOR   Descriptor = Object;
+    NTSTATUS                    status;
 
-        Context->HeadFreeReference = Descriptor->Next;
-        Descriptor->Next = GNTTAB_INVALID_REFERENCE;
-    }
+    if (!RangeSetIsEmpty(Context->RangeSet))
+        goto done;
 
-    Context->TailFreeReference = &Context->HeadFreeReference;
-}
+    status = __GnttabExpand(Context);
+    if (!NT_SUCCESS(status))
+        goto fail1;
 
-extern USHORT
-RtlCaptureStackBackTrace(
-    __in        ULONG   FramesToSkip,
-    __in        ULONG   FramesToCapture,
-    __out       PVOID   *BackTrace,
-    __out_opt   PULONG  BackTraceHash
-    );
+done:
+    Descriptor->Reference = (ULONG)RangeSetPop(Context->RangeSet);
 
-static NTSTATUS
-GnttabGet(
-    IN  PXENBUS_GNTTAB_CONTEXT  Context,
-    OUT PULONG                  Reference
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static VOID
+GnttabDescriptorDtor(
+    IN  PVOID                   Argument,
+    IN  PVOID                   Object
     )
 {
-    PGNTTAB_DESCRIPTOR          Descriptor;
-    KIRQL                       Irql;
+    PXENBUS_GNTTAB_CONTEXT      Context = Argument;
+    PXENBUS_GNTTAB_DESCRIPTOR   Descriptor = Object;
     NTSTATUS                    status;
 
-    KeAcquireSpinLock(&Context->Lock, &Irql);
-
-    if (!GNTTAB_IS_INVALID_REFERENCE(Context->HeadFreeReference))
-        goto done;
+    status = RangeSetPut(Context->RangeSet,
+                         (ULONGLONG)Descriptor->Reference,
+                         (ULONGLONG)Descriptor->Reference);
+    ASSERT(NT_SUCCESS(status));
+}
 
-    ASSERT3P(Context->TailFreeReference, ==, &Context->HeadFreeReference);
+static FORCEINLINE VOID
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__GnttabAcquireLock(
+    IN  PXENBUS_GNTTAB_CONTEXT  Context
+    )
+{
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
 
-    status = GnttabExpand(Context);
-    if (!NT_SUCCESS(status))
-        goto fail1;
+    KeAcquireSpinLockAtDpcLevel(&Context->Lock);
+}
 
-done:
-    ASSERT(!GNTTAB_IS_INVALID_REFERENCE(Context->HeadFreeReference));
+static DECLSPEC_NOINLINE VOID
+GnttabAcquireLock(
+    IN  PXENBUS_GNTTAB_CONTEXT  Context
+    )
+{
+    __GnttabAcquireLock(Context);
+}
 
-    *Reference = Context->HeadFreeReference;
-    Descriptor = &Context->Descriptor[*Reference];
+static FORCEINLINE VOID
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__GnttabReleaseLock(
+    IN  PXENBUS_GNTTAB_CONTEXT  Context
+    )
+{
+    ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
 
-    Context->HeadFreeReference = Descriptor->Next;
+#pragma prefast(disable:26110)
+    KeReleaseSpinLockFromDpcLevel(&Context->Lock);
+}
 
-    if (GNTTAB_IS_INVALID_REFERENCE(Context->HeadFreeReference))
-        Context->TailFreeReference = &Context->HeadFreeReference;
+static DECLSPEC_NOINLINE VOID
+GnttabReleaseLock(
+    IN  PXENBUS_GNTTAB_CONTEXT  Context
+    )
+{
+    __GnttabReleaseLock(Context);
+}
 
-    Descriptor->Next = GNTTAB_INVALID_REFERENCE;
+static FORCEINLINE NTSTATUS
+__GnttabFill(
+    IN  PXENBUS_GNTTAB_CONTEXT  Context
+    )
+{
+    NTSTATUS                    status;
 
-    ASSERT(IsZeroMemory(Descriptor, sizeof (GNTTAB_DESCRIPTOR)));
+    status = RangeSetInitialize(&Context->RangeSet);
+    if (!NT_SUCCESS(status))
+        goto fail1;
 
-    InsertTailList(&Context->List, &Descriptor->ListEntry);
+    status = PoolInitialize("GnttabDescriptor",
+                            sizeof (XENBUS_GNTTAB_DESCRIPTOR),
+                            GnttabDescriptorCtor,
+                            GnttabDescriptorDtor,
+                            GnttabAcquireLock,
+                            GnttabReleaseLock,
+                            Context,
+                            &Context->DescriptorPool);
+    if (!NT_SUCCESS(status))
+        goto fail2;
 
-    KeReleaseSpinLock(&Context->Lock, Irql);
+    return STATUS_SUCCESS;
 
-    (VOID) RtlCaptureStackBackTrace(1, 1, &Descriptor->Caller, NULL);    
+fail2:
+    Error("fail2\n");
 
-    return STATUS_SUCCESS;
+    RangeSetTeardown(Context->RangeSet);
+    Context->RangeSet = NULL;
 
 fail1:
     Error("fail1 (%08x)\n", status);
 
-    KeReleaseSpinLock(&Context->Lock, Irql);
-
     return status;
 }
 
-static VOID
-GnttabPut(
-    IN  PXENBUS_GNTTAB_CONTEXT  Context,
-    IN  ULONG                   Reference
+static FORCEINLINE VOID
+__GnttabEmpty(
+    IN  PXENBUS_GNTTAB_CONTEXT  Context
     )
 {
-    KIRQL                       Irql;
-    PGNTTAB_DESCRIPTOR          Descriptor;
+    ULONGLONG                   Entry;
 
-    ASSERT(!GNTTAB_IS_INVALID_REFERENCE(Reference));
+    PoolTeardown(Context->DescriptorPool);
+    Context->DescriptorPool = NULL;
 
-    Descriptor = &Context->Descriptor[Reference];
+    for (Entry = GNTTAB_RESERVED_ENTRY_COUNT;
+         Entry < Context->FrameCount * GNTTAB_ENTRY_PER_FRAME;
+         Entry++) {
+        NTSTATUS    status;
 
-    Descriptor->Caller = NULL;
-
-    KeAcquireSpinLock(&Context->Lock, &Irql);
-
-    RemoveEntryList(&Descriptor->ListEntry);
-    RtlZeroMemory(&Descriptor->ListEntry, sizeof (LIST_ENTRY));
-
-    ASSERT(IsZeroMemory(Descriptor, sizeof (GNTTAB_DESCRIPTOR)));
-
-    ASSERT(GNTTAB_IS_INVALID_REFERENCE(Descriptor->Next));
+        status = RangeSetGet(Context->RangeSet, Entry);
+        ASSERT(NT_SUCCESS(status));
+    }
 
-    *Context->TailFreeReference = Reference;
+    RangeSetTeardown(Context->RangeSet);
+    Context->RangeSet = NULL;
+}
 
-    ASSERT(GNTTAB_IS_INVALID_REFERENCE(Descriptor->Next));
-    Context->TailFreeReference = &Descriptor->Next;
+static PXENBUS_GNTTAB_DESCRIPTOR
+GnttabGet(
+    IN  PXENBUS_GNTTAB_CONTEXT  Context
+    )
+{
+    return PoolGet(Context->DescriptorPool, FALSE);
+}
 
-    KeReleaseSpinLock(&Context->Lock, Irql);
+static VOID
+GnttabPut(
+    IN  PXENBUS_GNTTAB_CONTEXT      Context,
+    IN  PXENBUS_GNTTAB_DESCRIPTOR   Descriptor
+    )
+{
+    PoolPut(Context->DescriptorPool, Descriptor, FALSE);
 }
 
 static FORCEINLINE NTSTATUS
 __GnttabPermitForeignAccessFullPage( 
-    IN  PXENBUS_GNTTAB_CONTEXT  Context,
-    IN  ULONG                   Reference,
-    IN  USHORT                  Domain,
-    IN  va_list                 Arguments
+    IN  PXENBUS_GNTTAB_CONTEXT      Context,
+    IN  PXENBUS_GNTTAB_DESCRIPTOR   Descriptor,
+    IN  USHORT                      Domain,
+    IN  va_list                     Arguments
     )
 {
-    PGNTTAB_DESCRIPTOR          Descriptor;
-    PFN_NUMBER                  Frame;
-    BOOLEAN                     ReadOnly;
-    grant_entry_v1_t            *Entry;
-
-    ASSERT(!GNTTAB_IS_INVALID_REFERENCE(Reference));
+    PFN_NUMBER                      Frame;
+    BOOLEAN                         ReadOnly;
+    grant_entry_v1_t                *Entry;
 
     Frame = va_arg(Arguments, PFN_NUMBER);
     ReadOnly = va_arg(Arguments, BOOLEAN);
 
-    Descriptor = &Context->Descriptor[Reference];
     ASSERT(IsZeroMemory(&Descriptor->Entry, sizeof (grant_entry_v1_t)));
 
     Descriptor->Entry.flags = (ReadOnly) ? GTF_readonly : 0;
@@ -278,7 +310,7 @@ __GnttabPermitForeignAccessFullPage(
     Descriptor->Entry.frame = (uint32_t)Frame;
     ASSERT3U(Descriptor->Entry.frame, ==, Frame);
 
-    Entry = &Context->Entry[Reference];
+    Entry = &Context->Entry[Descriptor->Reference];
 
     *Entry = Descriptor->Entry;
     KeMemoryBarrier();
@@ -292,7 +324,7 @@ __GnttabPermitForeignAccessFullPage(
 static NTSTATUS
 GnttabPermitForeignAccess(
     IN  PXENBUS_GNTTAB_CONTEXT      Context,
-    IN  ULONG                       Reference,
+    IN  PXENBUS_GNTTAB_DESCRIPTOR   Descriptor,
     IN  USHORT                      Domain,
     IN  XENBUS_GNTTAB_ENTRY_TYPE    Type,
     ...
@@ -304,7 +336,7 @@ GnttabPermitForeignAccess(
     va_start(Arguments, Type);
     switch (Type) {
     case GNTTAB_ENTRY_FULL_PAGE:
-        status =__GnttabPermitForeignAccessFullPage(Context, Reference, Domain, Arguments);
+        status =__GnttabPermitForeignAccessFullPage(Context, Descriptor, Domain, Arguments);
         break;
 
     default:
@@ -318,17 +350,16 @@ GnttabPermitForeignAccess(
 
 static NTSTATUS
 GnttabRevokeForeignAccess(
-    IN  PXENBUS_GNTTAB_CONTEXT  Context,
-    IN  ULONG                   Reference
+    IN  PXENBUS_GNTTAB_CONTEXT      Context,
+    IN  PXENBUS_GNTTAB_DESCRIPTOR   Descriptor
     )
 {
-    grant_entry_v1_t            *Entry;
-    volatile SHORT              *Flags;
-    PGNTTAB_DESCRIPTOR          Descriptor;
-    ULONG                       Attempt;
-    NTSTATUS                    status;
+    grant_entry_v1_t                *Entry;
+    volatile SHORT                  *Flags;
+    ULONG                           Attempt;
+    NTSTATUS                        status;
 
-    Entry = &Context->Entry[Reference];
+    Entry = &Context->Entry[Descriptor->Reference];
     Flags = (volatile SHORT *)&Entry->flags;
 
     Attempt = 0;
@@ -352,8 +383,6 @@ GnttabRevokeForeignAccess(
         goto fail1;
 
     RtlZeroMemory(Entry, sizeof (grant_entry_v1_t));
-
-    Descriptor = &Context->Descriptor[Reference];
     RtlZeroMemory(&Descriptor->Entry, sizeof (grant_entry_v1_t));
 
     return STATUS_SUCCESS;
@@ -364,79 +393,15 @@ fail1:
     return status;
 }
 
-static NTSTATUS
-GnttabCopy(
-    IN  PXENBUS_GNTTAB_CONTEXT          Context,
-    IN  PLIST_ENTRY                     List,
-    IN  ULONG                           Count
+static ULONG
+GnttabReference(
+    IN  PXENBUS_GNTTAB_CONTEXT      Context,
+    IN  PXENBUS_GNTTAB_DESCRIPTOR   Descriptor
     )
 {
-    struct gnttab_copy                  *op;
-    PLIST_ENTRY                         ListEntry;
-    ULONG                               Index;
-    NTSTATUS                            status;
-
     UNREFERENCED_PARAMETER(Context);
 
-    op = __GnttabAllocate(sizeof (struct gnttab_copy) * Count);
-
-    status = STATUS_NO_MEMORY;
-    if (op == NULL)
-        goto fail1;
-
-    Index = 0;
-    for (ListEntry = List->Flink;
-         ListEntry != List;
-         ListEntry = ListEntry->Flink) {
-        PXENBUS_GNTTAB_COPY_OPERATION   Operation;
-
-        Operation = CONTAINING_RECORD(ListEntry, XENBUS_GNTTAB_COPY_OPERATION, ListEntry);
-
-        ASSERT3U(Operation->Length, <=, PAGE_SIZE);
-        ASSERT3U(Operation->Offset + Operation->Length, <=, PAGE_SIZE);
-        ASSERT3U(Operation->RemoteOffset + Operation->Length, <=, PAGE_SIZE);
-
-        op[Index].source.domid = Operation->RemoteDomain;
-        op[Index].source.u.ref = Operation->RemoteReference;
-        op[Index].source.offset = (USHORT)Operation->RemoteOffset;
-
-        op[Index].dest.domid = DOMID_SELF;
-        op[Index].dest.u.gmfn = Operation->Pfn;
-        op[Index].dest.offset = (USHORT)Operation->Offset;
-
-        op[Index].len = (USHORT)Operation->Length;
-        op[Index].flags = GNTCOPY_source_gref;
-
-        Index++;
-    }
-    ASSERT3U(Index, ==, Count);
-
-    status = GrantTableCopy(op, Count);
-    if (!NT_SUCCESS(status))
-        goto fail2;
-
-    status = STATUS_UNSUCCESSFUL;
-    for (Index = 0; Index < Count; Index++) {
-        if (op[Index].status != 0)
-            goto fail3;
-    }
-
-    __GnttabFree(op);
-
-    return STATUS_SUCCESS;
-
-fail3:
-    Error("fail3\n");
-
-fail2:
-    Error("fail2\n");
-
-    __GnttabFree(op);
-
-fail1:
-    Error("fail1 (%08x)\n", status);
-
-    return status;
+    return (ULONG)Descriptor->Reference;
 }
 
 static VOID
@@ -513,6 +478,10 @@ GnttabDebugCallback(
     )
 {
     PXENBUS_GNTTAB_CONTEXT  Context = Argument;
+    ULONG                   Allocated;
+    ULONG                   MaximumAllocated;
+    ULONG                   Count;
+    ULONG                   MinimumCount;
 
     UNREFERENCED_PARAMETER(Crashing);
 
@@ -527,6 +496,26 @@ GnttabDebugCallback(
           Context->DebugCallback,
           "FrameCount = %u\n",
           Context->FrameCount);
+
+    PoolGetStatistics(Context->DescriptorPool,
+                      &Allocated,
+                      &MaximumAllocated,
+                      &Count,
+                      &MinimumCount);
+
+    DEBUG(Printf,
+          Context->DebugInterface,
+          Context->DebugCallback,
+          "DESCRIPTOR POOL: Allocated = %u (Maximum = %u)\n",
+          Allocated,
+          MaximumAllocated);
+
+    DEBUG(Printf,
+          Context->DebugInterface,
+          Context->DebugCallback,
+          "DESCRIPTOR POOL: Count = %u (Minimum = %u)\n",
+          Count,
+          MinimumCount);
 }
                      
 NTSTATUS
@@ -568,13 +557,9 @@ GnttabInitialize(
 
     Info("grant_entry_v1_t *: %p\n", Context->Entry);
 
-    InitializeListHead(&Context->List);
     KeInitializeSpinLock(&Context->Lock);
 
-    ASSERT(GNTTAB_IS_INVALID_REFERENCE(Context->HeadFreeReference));
-    Context->TailFreeReference = &Context->HeadFreeReference;
-
-    GnttabExpand(Context);
+    __GnttabFill(Context);
 
     Context->SuspendInterface = FdoGetSuspendInterface(Fdo);
 
@@ -628,10 +613,7 @@ fail3:
 
     __GnttabEmpty(Context);
 
-    Context->TailFreeReference = NULL;
-
     RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
-    RtlZeroMemory(&Context->List, sizeof (LIST_ENTRY));
 
     Context->Entry = NULL;
 
@@ -663,9 +645,6 @@ GnttabTeardown(
 
     Trace("====>\n");
 
-    if (!IsListEmpty(&Context->List))
-        BUG("OUTSTANDING REFERENCES");
-
     DEBUG(Deregister,
           Context->DebugInterface,
           Context->DebugCallback);
@@ -684,10 +663,7 @@ GnttabTeardown(
 
     __GnttabEmpty(Context);
 
-    Context->TailFreeReference = NULL;
-
     RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
-    RtlZeroMemory(&Context->List, sizeof (LIST_ENTRY));
 
     Context->Entry = NULL;
 
diff --git a/src/xenbus/pool.c b/src/xenbus/pool.c
new file mode 100644 (file)
index 0000000..0c7c2e0
--- /dev/null
@@ -0,0 +1,542 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, 
+ * with or without modification, are permitted provided 
+ * that the following conditions are met:
+ * 
+ * *   Redistributions of source code must retain the above 
+ *     copyright notice, this list of conditions and the 
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above 
+ *     copyright notice, this list of conditions and the 
+ *     following disclaimer in the documentation and/or other 
+ *     materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE.
+ */
+
+#include <ntddk.h>
+#include <ntstrsafe.h>
+#include <util.h>
+
+#include "pool.h"
+#include "dbg_print.h"
+#include "assert.h"
+
+#define POOL_POOL   'OBJE'
+
+typedef struct _OBJECT_HEADER {
+    ULONG       Magic;
+
+#define OBJECT_HEADER_MAGIC 0x02121996
+
+    LIST_ENTRY  ListEntry;
+} OBJECT_HEADER, *POBJECT_HEADER;
+
+#define MAXIMUM_SLOTS   6
+
+typedef struct _POOL_MAGAZINE {
+    PVOID   Slot[MAXIMUM_SLOTS];
+} POOL_MAGAZINE, *PPOOL_MAGAZINE;
+
+struct _XENBUS_POOL {
+    const CHAR      *Name;
+    ULONG           Size;
+    NTSTATUS        (*Ctor)(PVOID, PVOID);
+    VOID            (*Dtor)(PVOID, PVOID);
+    VOID            (*AcquireLock)(PVOID);
+    VOID            (*ReleaseLock)(PVOID);
+    PVOID           Argument;
+    KTIMER          Timer;
+    KDPC            Dpc;
+    LIST_ENTRY      GetList;
+    PLIST_ENTRY     PutList;
+    POOL_MAGAZINE   Magazine[MAXIMUM_PROCESSORS];
+    LONG            Allocated;
+    LONG            MaximumAllocated;
+    LONG            Count;
+    LONG            MinimumCount;
+};
+
+static FORCEINLINE PVOID
+__PoolAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocateNonPagedPoolWithTag(Length, POOL_POOL);
+}
+
+static FORCEINLINE VOID
+__PoolFree(
+    IN  PVOID   Buffer
+    )
+{
+    __FreePoolWithTag(Buffer, POOL_POOL);
+}
+
+static FORCEINLINE VOID
+__PoolSwizzle(
+    IN  PXENBUS_POOL    Pool
+    )
+{
+    PLIST_ENTRY         ListEntry;
+
+    ListEntry = InterlockedExchangePointer(&Pool->PutList, NULL);
+
+    while (ListEntry != NULL) {
+        PLIST_ENTRY Next;
+
+        Next = ListEntry->Flink;
+        ListEntry->Flink = NULL;
+        ASSERT3P(ListEntry->Blink, ==, NULL);
+
+        InsertTailList(&Pool->GetList, ListEntry);
+
+        ListEntry = Next;
+    }
+}
+
+static FORCEINLINE PVOID
+__PoolGetShared(
+    IN  PXENBUS_POOL    Pool,
+    IN  BOOLEAN         Locked
+    )
+{
+    LONG                Count;
+    POBJECT_HEADER      Header;
+    PVOID               Object;
+    LONG                Allocated;
+    NTSTATUS            status;
+
+    Count = InterlockedDecrement(&Pool->Count);
+
+    if (Count >= 0) {
+        PLIST_ENTRY     ListEntry;
+
+        if (!Locked)
+            Pool->AcquireLock(Pool->Argument);
+
+        if (Count < Pool->MinimumCount)
+            Pool->MinimumCount = Count;
+
+        if (IsListEmpty(&Pool->GetList))
+            __PoolSwizzle(Pool);
+
+        ListEntry = RemoveHeadList(&Pool->GetList);
+        ASSERT(ListEntry != &Pool->GetList);
+
+        if (!Locked)
+            Pool->ReleaseLock(Pool->Argument);
+
+        RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+        Header = CONTAINING_RECORD(ListEntry, OBJECT_HEADER, ListEntry);
+        ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
+
+        Object = Header + 1;
+        goto done;
+    }
+
+    (VOID) InterlockedIncrement(&Pool->Count);
+
+    Header = __PoolAllocate(sizeof (OBJECT_HEADER) + Pool->Size);
+
+    status = STATUS_NO_MEMORY;
+    if (Header == NULL)
+        goto fail1;
+
+    Header->Magic = OBJECT_HEADER_MAGIC;
+
+    Object = Header + 1;
+
+    status = Pool->Ctor(Pool->Argument, Object);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    Allocated = InterlockedIncrement(&Pool->Allocated);
+
+    if (Allocated > Pool->MaximumAllocated) {
+        if (!Locked)
+            Pool->AcquireLock(Pool->Argument);
+
+        if (Allocated > Pool->MaximumAllocated)
+            Pool->MaximumAllocated = Allocated;
+
+        if (!Locked)
+            Pool->ReleaseLock(Pool->Argument);
+    }
+
+done:
+    return Object;
+
+fail2:
+    Error("fail2\n");
+
+    Header->Magic = 0;
+
+    ASSERT(IsZeroMemory(Header, sizeof (OBJECT_HEADER)));
+    __PoolFree(Header);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return NULL;    
+}
+
+static FORCEINLINE VOID
+__PoolPutShared(
+    IN  PXENBUS_POOL    Pool,
+    IN  PVOID           Object,
+    IN  BOOLEAN         Locked
+    )
+{
+    POBJECT_HEADER      Header;
+    PLIST_ENTRY         Old;
+    PLIST_ENTRY         New;
+
+    ASSERT(Object != NULL);
+
+    Header = Object;
+    --Header;
+    ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
+
+    ASSERT(IsZeroMemory(&Header->ListEntry, sizeof (LIST_ENTRY)));
+
+    if (!Locked) {
+        New = &Header->ListEntry;
+
+        do {
+            Old = Pool->PutList;
+            New->Flink = Old;
+        } while (InterlockedCompareExchangePointer(&Pool->PutList, New, Old) != Old);
+    } else {
+        InsertTailList(&Pool->GetList, &Header->ListEntry);
+    }
+
+    KeMemoryBarrier();
+
+    (VOID) InterlockedIncrement(&Pool->Count);
+}
+
+static FORCEINLINE PVOID
+__PoolGetMagazine(
+    IN  PXENBUS_POOL    Pool,
+    IN  ULONG           Cpu
+    )
+{
+    PPOOL_MAGAZINE      Magazine;
+    ULONG               Index;
+
+    Magazine = &Pool->Magazine[Cpu];
+
+    for (Index = 0; Index < MAXIMUM_SLOTS; Index++) {
+        PVOID   Object;
+
+        if (Magazine->Slot[Index] != NULL) {
+            Object = Magazine->Slot[Index];
+            Magazine->Slot[Index] = NULL;
+
+            return Object;
+        }
+    }
+
+    return NULL;
+}
+
+static FORCEINLINE BOOLEAN
+__PoolPutMagazine(
+    IN  PXENBUS_POOL    Pool,
+    IN  ULONG           Cpu,
+    IN  PVOID           Object
+    )
+{
+    PPOOL_MAGAZINE      Magazine;
+    ULONG               Index;
+
+    Magazine = &Pool->Magazine[Cpu];
+
+    for (Index = 0; Index < MAXIMUM_SLOTS; Index++) {
+        if (Magazine->Slot[Index] == NULL) {
+            Magazine->Slot[Index] = Object;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+PVOID
+PoolGet(
+    IN  PXENBUS_POOL    Pool,
+    IN  BOOLEAN         Locked
+    )
+{
+    KIRQL               Irql;
+    ULONG               Cpu;
+    PVOID               Object;
+
+    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+    Cpu = KeGetCurrentProcessorNumber();
+
+    Object = __PoolGetMagazine(Pool, Cpu);
+    if (Object == NULL)
+        Object = __PoolGetShared(Pool, Locked);
+
+    KeLowerIrql(Irql);
+
+    return Object;
+}
+
+VOID
+PoolPut(
+    IN  PXENBUS_POOL    Pool,
+    IN  PVOID           Object,
+    IN  BOOLEAN         Locked
+    )
+{
+    KIRQL               Irql;
+    ULONG               Cpu;
+
+    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+    Cpu = KeGetCurrentProcessorNumber();
+
+    if (!__PoolPutMagazine(Pool, Cpu, Object))
+        __PoolPutShared(Pool, Object, Locked);
+
+    KeLowerIrql(Irql);
+}
+
+VOID
+PoolGetStatistics(
+    IN  PXENBUS_POOL    Pool,
+    OUT PULONG          Allocated,
+    OUT PULONG          MaximumAllocated,
+    OUT PULONG          Count,
+    OUT PULONG          MinimumCount
+    )
+{
+    *Allocated = Pool->Allocated;
+    *MaximumAllocated = Pool->MaximumAllocated;
+
+    *Count = Pool->Count;
+    *MinimumCount = Pool->MinimumCount;
+}
+
+static FORCEINLINE
+__PoolFlushMagazines(
+    IN  PXENBUS_POOL    Pool
+    )
+{
+    ULONG               Cpu;
+
+    for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
+        PVOID   Object;
+
+        while ((Object = __PoolGetMagazine(Pool, Cpu)) != NULL)
+            __PoolPutShared(Pool, Object, TRUE);
+    }
+}
+
+static FORCEINLINE VOID
+__PoolTrimShared(
+    IN      PXENBUS_POOL    Pool,
+    IN OUT  PLIST_ENTRY     List
+    )
+{
+    LONG                    Count;
+    LONG                    Excess;
+
+    Count = Pool->Count;
+
+    KeMemoryBarrier();
+
+    Excess = Pool->MinimumCount;
+
+    while (Excess != 0) {
+        PLIST_ENTRY     ListEntry;
+
+        Count = InterlockedDecrement(&Pool->Count);
+        if (Count < 0) {
+            Count = InterlockedIncrement(&Pool->Count);
+            break;
+        }
+
+        if (IsListEmpty(&Pool->GetList))
+            __PoolSwizzle(Pool);
+
+        ListEntry = RemoveHeadList(&Pool->GetList);
+        ASSERT(ListEntry != &Pool->GetList);
+
+        InsertTailList(List, ListEntry);
+
+        InterlockedDecrement(&Pool->Allocated);
+        --Excess;
+    }
+
+    Pool->MinimumCount = Count;
+}
+
+static FORCEINLINE VOID
+__PoolEmpty(
+    IN      PXENBUS_POOL    Pool,
+    IN OUT  PLIST_ENTRY     List
+    )
+{
+    while (!IsListEmpty(List)) {
+        PLIST_ENTRY     ListEntry;
+        POBJECT_HEADER  Header;
+        PVOID           Object;
+
+        ListEntry = RemoveHeadList(List);
+        RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+        Header = CONTAINING_RECORD(ListEntry, OBJECT_HEADER, ListEntry);
+        ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
+
+        Object = Header + 1;
+
+        Pool->Dtor(Pool->Argument, Object);
+
+        Header->Magic = 0;
+
+        ASSERT(IsZeroMemory(Header, sizeof (OBJECT_HEADER)));
+        __PoolFree(Header);
+    }
+}
+
+#define TIME_US(_us)        ((_us) * 10)
+#define TIME_MS(_ms)        (TIME_US((_ms) * 1000))
+#define TIME_RELATIVE(_t)   (-(_t))
+
+#define POOL_PERIOD  1000
+
+KDEFERRED_ROUTINE   PoolDpc;
+
+VOID
+PoolDpc(
+    IN  PKDPC       Dpc,
+    IN  PVOID       Context,
+    IN  PVOID       Argument1,
+    IN  PVOID       Argument2
+    )
+{
+    PXENBUS_POOL    Pool = Context;
+    LIST_ENTRY      List;
+
+    UNREFERENCED_PARAMETER(Dpc);
+    UNREFERENCED_PARAMETER(Argument1);
+    UNREFERENCED_PARAMETER(Argument2);
+
+    InitializeListHead(&List);
+
+    Pool->AcquireLock(Pool->Argument);
+    __PoolTrimShared(Pool, &List);
+    Pool->ReleaseLock(Pool->Argument);
+
+    __PoolEmpty(Pool, &List);
+    ASSERT(IsListEmpty(&List));
+}
+
+NTSTATUS
+PoolInitialize(
+    IN  const CHAR      *Name,
+    IN  ULONG           Size,
+    IN  NTSTATUS        (*Ctor)(PVOID, PVOID),
+    IN  VOID            (*Dtor)(PVOID, PVOID),
+    IN  VOID            (*AcquireLock)(PVOID),
+    IN  VOID            (*ReleaseLock)(PVOID),
+    IN  PVOID           Argument,
+    OUT PXENBUS_POOL    *Pool
+    )
+{
+    LARGE_INTEGER       Timeout;
+    NTSTATUS            status;
+
+    *Pool = __PoolAllocate(sizeof (XENBUS_POOL));
+
+    status = STATUS_NO_MEMORY;
+    if (*Pool == NULL)
+        goto fail1;
+
+    (*Pool)->Name = Name;
+    (*Pool)->Size = Size;
+    (*Pool)->Ctor = Ctor;
+    (*Pool)->Dtor = Dtor;
+    (*Pool)->AcquireLock = AcquireLock;
+    (*Pool)->ReleaseLock = ReleaseLock;
+    (*Pool)->Argument = Argument;
+
+    InitializeListHead(&(*Pool)->GetList);
+
+    KeInitializeDpc(&(*Pool)->Dpc,
+                    PoolDpc,
+                    (*Pool));
+
+    Timeout.QuadPart = TIME_RELATIVE(TIME_MS(POOL_PERIOD));
+
+    KeInitializeTimer(&(*Pool)->Timer);
+    KeSetTimerEx(&(*Pool)->Timer,
+                 Timeout,
+                 POOL_PERIOD,
+                 &(*Pool)->Dpc);
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;    
+}
+
+VOID
+PoolTeardown(
+    IN  PXENBUS_POOL    Pool
+    )
+{
+    LIST_ENTRY          List;
+
+    KeCancelTimer(&Pool->Timer);
+    KeFlushQueuedDpcs();
+
+    RtlZeroMemory(&Pool->Timer, sizeof (KTIMER));
+    RtlZeroMemory(&Pool->Dpc, sizeof (KDPC));
+
+    InitializeListHead(&List);
+
+    __PoolFlushMagazines(Pool);
+
+    Pool->MinimumCount = Pool->Count;
+    __PoolTrimShared(Pool, &List);
+    __PoolEmpty(Pool, &List);
+
+    ASSERT3U(Pool->Count, ==, 0);
+    ASSERT3U(Pool->Allocated, ==, 0);
+    Pool->MaximumAllocated = 0;
+
+    RtlZeroMemory(&Pool->GetList, sizeof (LIST_ENTRY));
+
+    Pool->Argument = NULL;
+    Pool->ReleaseLock = NULL;
+    Pool->AcquireLock = NULL;
+    Pool->Dtor = NULL;
+    Pool->Ctor = NULL;
+    Pool->Size = 0;
+    Pool->Name = NULL;
+
+    ASSERT(IsZeroMemory(Pool, sizeof (XENBUS_POOL)));
+    __PoolFree(Pool);
+}
diff --git a/src/xenbus/pool.h b/src/xenbus/pool.h
new file mode 100644 (file)
index 0000000..89e3f6c
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, 
+ * with or without modification, are permitted provided 
+ * that the following conditions are met:
+ * 
+ * *   Redistributions of source code must retain the above 
+ *     copyright notice, this list of conditions and the 
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above 
+ *     copyright notice, this list of conditions and the 
+ *     following disclaimer in the documentation and/or other 
+ *     materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENBUS_POOL_H
+#define _XENBUS_POOL_H
+
+#include <ntddk.h>
+
+typedef struct _XENBUS_POOL XENBUS_POOL, *PXENBUS_POOL;
+
+extern NTSTATUS
+PoolInitialize(
+    IN  const CHAR      *Name,
+    IN  ULONG           Size,
+    IN  NTSTATUS        (*Ctor)(PVOID, PVOID),
+    IN  VOID            (*Dtor)(PVOID, PVOID),
+    IN  VOID            (*AcquireLock)(PVOID),
+    IN  VOID            (*ReleaseLock)(PVOID),
+    IN  PVOID           Argument,
+    OUT PXENBUS_POOL    *Pool
+    );
+
+extern VOID
+PoolTeardown(
+    IN  PXENBUS_POOL    Pool
+    );
+
+extern PVOID
+PoolGet(
+    IN  PXENBUS_POOL    Pool,
+    IN  BOOLEAN         Locked
+    );
+
+extern VOID
+PoolPut(
+    IN  PXENBUS_POOL    Pool,
+    IN  PVOID           Object,
+    IN  BOOLEAN         Locked
+    );
+
+extern VOID
+PoolGetStatistics(
+    IN  PXENBUS_POOL    Pool,
+    OUT PULONG          Allocated,
+    OUT PULONG          MaximumAllocated,
+    OUT PULONG          Count,
+    OUT PULONG          MinimumCount
+    );
+
+#endif  // _XENBUS_POOL_H
index 7e55b2d5789c6a794e474f7d0a1ee613548d803e..24f63bd992efe9582d3e5aacc1991c820471d765 100644 (file)
@@ -179,6 +179,14 @@ __RangeSetMergeForwards(
     __RangeSetRemove(RangeSet, TRUE);
 }
 
+BOOLEAN
+RangeSetIsEmpty(
+    IN  PXENBUS_RANGE_SET   RangeSet
+    )
+{
+    return IsListEmpty(&RangeSet->List);
+}
+
 ULONGLONG
 RangeSetPop(
     IN  PXENBUS_RANGE_SET   RangeSet
index fadd476eae4a535ee3b7db4900f2e852f3777733..80209dac07cd4aa5a70b822be044570fc9145580 100644 (file)
 
 typedef struct _XENBUS_RANGE_SET   XENBUS_RANGE_SET, *PXENBUS_RANGE_SET;
 
+extern BOOLEAN
+RangeSetIsEmpty(
+    IN  PXENBUS_RANGE_SET   RangeSet
+    );
+
 extern ULONGLONG
 RangeSetPop(
     IN  PXENBUS_RANGE_SET   RangeSet