[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Rework CACHE to use a FreeList


  • To: <win-pv-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Owen Smith <owen.smith@xxxxxxxxxx>
  • Date: Fri, 19 Aug 2022 11:15:18 +0100
  • Authentication-results: esa2.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none
  • Cc: Owen Smith <owen.smith@xxxxxxxxxx>
  • Delivery-date: Fri, 19 Aug 2022 10:16:00 +0000
  • Ironport-data: A9a23:C9DDv6OuYp4qVzTvrXNrnJalp4KmJRAgMBhcexONyBt+GVwur4U6qh/6T4CrNlZ+wcLBcFX+XO/GdP4ujdB5oVkUQOsQSOR9V4+ZFEiTsBugcdgL6eDCZ6ywInw63Rn1V9M2EA4hsCIr6SMTmN7IVVWAxZdYdlaoaqQjx6lqOSLSgkUM8TyHer6x9JnOlKEqTp72CIohrtmY/d5C6A2tLGGZGFovy9l35YsOTBdErek8bLWIEf42heD/4K6Pabi+2KsmSU7QwJUvqDMPBXkw8l6r6YOKEbvbspNEdp51l0McyEfCesOnJOewvvNefmA2OGq4UY3fYNTzVwkmspo1mxahGJkT2sIpD2ygZ0i0jddb98y4w2jW4MuLqDwhkFyKDb2zrYE/37XzRjsn68Uu8LW53lwFNwn0rMeByCDSJzdOmXoDsU+KWL+epGFG3fY7B9mpCe8njNAHrQ7vt8FiWA0A6h366kFJ4K8Nvnl/U1k0Cu4sJQpQgrQRq2pn5T8cdXbH2OIsxWrxe/+DNqt8ZaQxJlSWCFBX8fATdwTs00VlUbZn2SC3H0RaePdK6Kpy7qQ/PgFsEqhoLZjAr17fgGp18bz2JifYGZVWoYx4xizNJmJlz/0Md5kcUXkSKsOcJ9IQNbgJkF3pXCs2ZOVKi9JliWCZFyiS/fyW30f4lZlZ81h9HvB3tZiHWtyz24Nv7mjztShNA69pvRw8UVKE4GTEy/vmWsgn8ajb7oXXF272NWPhlbMQlBOHfkctSm2M+do8upLyE4cEIvdCEVQWudZZejvqyCn+bWRtbl7Cy1NnonzG7CAiuprvxbkbv8cLxYxbVAM9TAjdq2xWAbPbPdQipDvuPn2PiOCYdS/ubBsz9xAkFJYczD7qwMvqBPUywkfLTK3jmnIiJLYjDt+UKxDcXAslkVh7gfUuG1plnTeH/Ulbm3WotEk6Y+nDd+1KuJNgIFgzSE7YwLlDRu5KC9pqRiC4o9gP10UDgMvMsQYZq/Rg3Fu2JMCa8hWzyLCZYhV5Aq6Fr91AssUim+3gUcw10r8+Y0xzD+YLO0L/iB8HzoNljJy7YqLqI9feSkH71DKe4/1TtJhCS0MZgOHigfwDkvIXIu+/GTggnsrEtLBZb6gF/5aULTOJLsf4uaZly0YEurP0b1KcEjCej4aLIX9LIrWGErHw6SrYE4cY3YwKHcOMr2gU2460CdU6sixCzO1bd1MtcjGi0g8fNQk9L717eVLS71fBAezxxya2r8n38uu0WJ3Kur9hD2sxslC0jI8gpgLM9p4AHE1/3TUR4mxtkNunYLbLtbcohYci3jZMYf77PtiG7XegplVpOUAsORwM66UosO7XERUxU4Wu9XNqhalGIuojnN6nuEqXxBzcjjpdp+SrlwQOn7CTWgN6uBdNlv02lYu63IFoPQLmRTYxTZXNeqCpMMl83Hshl8pdI30mupSJ8aE86wt7/fHAbS39a0RyOfUH0BxsrDCschS6O6rGEttdR0uylw6JGXHzZGbsA1doHOjEbR0Sy+JNcHBlfk3GZqp9Pt91nz+AJxjIuBNIl0tPV9j4e8OpgRmcF0OrfXXWJqe0eYh353T88QR5rSeIBtMZxZF1aH5RVUXwSdcX6ergAfgRte8GT108L2jSutsy8da0UoZnq3u2cuECBxcPGrStvfFqyudOG3Hd6lYGNy8ksdJLM+KS5j2WeNsIq1Ca03H93KCqUd0y5UIDsIRKgGIaMlo9p0q0CWiL7kL198lcV1CdHosy7p1ehIgxdG3DYEKnnHZjwiX6tlhIS+RuCDmKBakkMMf2QTyM3M5l+kvkhZs8bToTNKkYW22HAJkqd3K/7hAAil0ddOnfqd/9iqfGH0qm7HXawZM1YWcHHsP03nyjv6PJ/8LpnYewcbkXGce7jiYg0cazv1oFAvX3s04H5M+4w4gjmPBM+XLn1mqW4nW9iX2YHnRbeXArUIScHV/8p4Hp88uHwzy0/c6ahpC8qxTGzr2jRaFUlY/oMVu/F9LnY60N+c6ANH5Qtw52hb3SWmOkZeEViUG05IBZRRDeT3izDOTbKVIyiF8NxiYGxxdr0IQA/jP3ZJwMNgYzmJdfAMEZFsniuY0Au1yjv+SQEi7mpRQhlJ68p6CRjK4oNAnt5Rgm5r6PI5ALx6mi3VnZHKbS+aJBrB0inXIGlLCxuZpnR4oEVnjgvBpaA9el74S2sNIGrf7LT43rb1ES7CLx7WQ7fz7DRRdECuG5Vmnig3IFvcrHh69xSoRk9/uE55XZD2t2IsUZng4QBnNStr9gqTaFPTC4L1/MbpxXtYowtXV51Tj7V3yi9sSJFazxUySZOGQTRJsm/1FrqxEdqMxEeTwt8QrAXsePnHZ3/lpp83yO4BL2bPEjHt6WoyPIYvjZI5w1idzSq2D0AuhywZjza0HmAdH9rIH5jKxhsynVcEYAKGGAldboluqZqFJXcVIjNb8Tp5FgG/6ea/x4n3+npumY//zaKEtiDHjCBmvaomL1xVvmn8zSb3y8Nqq7mU25rho=
  • List-id: Developer list for the Windows PV Drivers subproject <win-pv-devel.lists.xenproject.org>

The slab allocation method will allogate about a PAGE worth of objects, and
every object will be initialized. If the objects initializer allocates any
resources, this can result in resource starvation. A particular bad example of
this is the grant table cache, where a page of gnttab objects is 253 objects.
This is highlighted by xenvif's queues, where the receiver requires 257 grant
references (1 for the ring, and 256 for the ring slots) which results in 2 
slabs,
or 506 gnttab objects, reserving 506 grant references.

Use a FreeList to contain individual objects that are not in use. This trades
an increase in smaller allocations for reducing the wastage of unused objects.

Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
 src/xenbus/cache.c | 674 ++++++++++++---------------------------------
 1 file changed, 178 insertions(+), 496 deletions(-)

diff --git a/src/xenbus/cache.c b/src/xenbus/cache.c
index 13fb0e5..d5500a4 100644
--- a/src/xenbus/cache.c
+++ b/src/xenbus/cache.c
@@ -52,20 +52,12 @@ typedef struct _XENBUS_CACHE_MAGAZINE {
     PVOID   Slot[XENBUS_CACHE_MAGAZINE_SLOTS];
 } XENBUS_CACHE_MAGAZINE, *PXENBUS_CACHE_MAGAZINE;
 
-
-#define XENBUS_CACHE_SLAB_MAGIC 'BALS'
-
-typedef struct _XENBUS_CACHE_SLAB {
-    ULONG           Magic;
+typedef struct _XENBUS_CACHE_HEADER {
     PXENBUS_CACHE   Cache;
     LIST_ENTRY      ListEntry;
-    USHORT          MaximumOccupancy;
-    USHORT          CurrentOccupancy;
-    ULONG           *Mask;
     UCHAR           Buffer[1];
-} XENBUS_CACHE_SLAB, *PXENBUS_CACHE_SLAB;
+} XENBUS_CACHE_HEADER, *PXENBUS_CACHE_HEADER;
 
-#define BITS_PER_ULONG  (sizeof (ULONG) * 8)
 #define MAXNAMELEN      128
 
 struct _XENBUS_CACHE {
@@ -79,13 +71,12 @@ struct _XENBUS_CACHE {
     VOID                    (*AcquireLock)(PVOID);
     VOID                    (*ReleaseLock)(PVOID);
     PVOID                   Argument;
-    LIST_ENTRY              SlabList;
-    PLIST_ENTRY             Cursor;
-    ULONG                   Count;
-    PXENBUS_CACHE_MAGAZINE  Magazine;
+    PXENBUS_CACHE_MAGAZINE  Magazines;
     ULONG                   MagazineCount;
-    LONG                    CurrentSlabs;
-    LONG                    MaximumSlabs;
+    KSPIN_LOCK              FreeLock;
+    LIST_ENTRY              FreeList;
+    LONG                    FreeSize;
+    LONG                    Count;
     LONG                    CurrentObjects;
     LONG                    MaximumObjects;
 };
@@ -156,372 +147,197 @@ __CacheDtor(
     Cache->Dtor(Cache->Argument, Object);
 }
 
-static PVOID
-CacheGetObjectFromMagazine(
-    IN  PXENBUS_CACHE_MAGAZINE  Magazine
-    )
-{
-    ULONG                       Index;
-
-    for (Index = 0; Index < XENBUS_CACHE_MAGAZINE_SLOTS; Index++) {
-        PVOID   Object;
-
-        if (Magazine->Slot[Index] != NULL) {
-            Object = Magazine->Slot[Index];
-            Magazine->Slot[Index] = NULL;
-
-            return Object;
-        }
-    }
-
-    return NULL;
-}
-
+// Lock must be held
 static NTSTATUS
-CachePutObjectToMagazine(
-    IN  PXENBUS_CACHE_MAGAZINE  Magazine,
-    IN  PVOID                   Object
-    )
-{
-    ULONG                       Index;
-
-    for (Index = 0; Index < XENBUS_CACHE_MAGAZINE_SLOTS; Index++) {
-        if (Magazine->Slot[Index] == NULL) {
-            Magazine->Slot[Index] = Object;
-            return STATUS_SUCCESS;
-        }
-    }
-
-    return STATUS_UNSUCCESSFUL;
-}
-
-static VOID
-CacheInsertSlab(
+CacheFill(
     IN  PXENBUS_CACHE       Cache,
-    IN  PXENBUS_CACHE_SLAB  New
-    )
-{
-#define INSERT_BEFORE(_ListEntry, _New)             \
-        do {                                        \
-            (_New)->Blink = (_ListEntry)->Blink;    \
-            (_ListEntry)->Blink->Flink = (_New);    \
-                                                    \
-            (_ListEntry)->Blink = (_New);           \
-            (_New)->Flink = (_ListEntry);           \
-        } while (FALSE)
-
-    PLIST_ENTRY             ListEntry;
-
-    ASSERT(New->CurrentOccupancy < New->MaximumOccupancy);
-
-    Cache->Cursor = NULL;
-
-    for (ListEntry = Cache->SlabList.Flink;
-         ListEntry != &Cache->SlabList;
-         ListEntry = ListEntry->Flink) {
-        PXENBUS_CACHE_SLAB  Slab;
-
-        Slab = CONTAINING_RECORD(ListEntry, XENBUS_CACHE_SLAB, ListEntry);
-
-        if (Slab->CurrentOccupancy < New->CurrentOccupancy) {
-            INSERT_BEFORE(ListEntry, &New->ListEntry);
-            goto done;
-        }
-
-        if (Slab->CurrentOccupancy < Slab->MaximumOccupancy &&
-            Cache->Cursor == NULL)
-            Cache->Cursor = ListEntry;
-    }
-
-    InsertTailList(&Cache->SlabList, &New->ListEntry);
-
-done:
-    if (Cache->Cursor == NULL)
-        Cache->Cursor = &New->ListEntry;
-
-#undef  INSERT_BEFORE
-}
-
-#if DBG
-static VOID
-CacheAudit(
-    IN  PXENBUS_CACHE   Cache
+    IN  ULONG               Target
     )
 {
-    ULONG               CurrentOccupancy = ULONG_MAX;
-    PLIST_ENTRY         ListEntry;
-
-    //
-    // The cursror should point at the first slab that is not fully
-    // occupied.
-    //
-    for (ListEntry = Cache->SlabList.Flink;
-         ListEntry != &Cache->SlabList;
-         ListEntry = ListEntry->Flink) {
-        PXENBUS_CACHE_SLAB  Slab;
-
-        Slab = CONTAINING_RECORD(ListEntry, XENBUS_CACHE_SLAB, ListEntry);
-
-        if (Slab->CurrentOccupancy < Slab->MaximumOccupancy) {
-            ASSERT3P(Cache->Cursor, ==, ListEntry);
-            break;
-        }
-    }
-
-    // Slabs should be kept in order of maximum to minimum occupancy
-    for (ListEntry = Cache->SlabList.Flink;
-         ListEntry != &Cache->SlabList;
-         ListEntry = ListEntry->Flink) {
-        PXENBUS_CACHE_SLAB  Slab;
-
-        Slab = CONTAINING_RECORD(ListEntry, XENBUS_CACHE_SLAB, ListEntry);
-
-        ASSERT3U(Slab->CurrentOccupancy, <=, CurrentOccupancy);
-
-        CurrentOccupancy = Slab->CurrentOccupancy;
-    }
-}
-#else
-#define CacheAudit(_Cache) ((VOID)(_Cache))
-#endif
-
-// Must be called with lock held
-static NTSTATUS
-CacheCreateSlab(
-    IN  PXENBUS_CACHE   Cache
-    )
-{
-    PXENBUS_CACHE_SLAB  Slab;
-    ULONG               NumberOfBytes;
-    ULONG               Count;
-    ULONG               Size;
-    LONG                Index;
-    LONG                SlabCount;
-    NTSTATUS            status;
-
-    NumberOfBytes = P2ROUNDUP(FIELD_OFFSET(XENBUS_CACHE_SLAB, Buffer) +
-                              Cache->Size,
-                              PAGE_SIZE);
-    Count = (NumberOfBytes - FIELD_OFFSET(XENBUS_CACHE_SLAB, Buffer)) /
-            Cache->Size;
-    ASSERT(Count != 0);
-
-    status = STATUS_INSUFFICIENT_RESOURCES;
-    if (Cache->Count + Count > Cache->Cap)
-        goto fail1;
-
-    Slab = __CacheAllocate(NumberOfBytes);
-    ASSERT3P(Slab, ==, PAGE_ALIGN(Slab));
-
-    status = STATUS_NO_MEMORY;
-    if (Slab == NULL)
-        goto fail2;
-
-    RtlZeroMemory(Slab, NumberOfBytes);
+    ULONG                   Size;
+    PXENBUS_CACHE_HEADER    Header;
+    NTSTATUS                status;
 
-    Slab->Magic = XENBUS_CACHE_SLAB_MAGIC;
-    Slab->Cache = Cache;
-    Slab->MaximumOccupancy = (USHORT)Count;
+    Size = P2ROUNDUP(FIELD_OFFSET(XENBUS_CACHE_HEADER, Buffer) + Cache->Size,
+                     sizeof(ULONG_PTR));
 
-    Size = P2ROUNDUP(Count, BITS_PER_ULONG);
-    Size /= 8;
+    while (Cache->Count < (LONG)Target) {
+        status = STATUS_NO_MEMORY;
 
-    Slab->Mask = __CacheAllocate(Size);
-    if (Slab->Mask == NULL)
-        goto fail3;
+        Header = __CacheAllocate(Size);
+        if (Header == NULL)
+            goto fail1;
 
-    for (Index = 0; Index < (LONG)Slab->MaximumOccupancy; Index++) {
-        PVOID Object = (PVOID)&Slab->Buffer[Index * Cache->Size];
+        Header->Cache = Cache;
+        InitializeListHead(&Header->ListEntry);
 
-        status = __CacheCtor(Cache, Object);
+        status = __CacheCtor(Cache, Header->Buffer);
         if (!NT_SUCCESS(status))
-            goto fail4;
-    }
-
-    CacheInsertSlab(Cache, Slab);
-    Cache->Count += Count;
-
-    SlabCount = InterlockedIncrement(&Cache->CurrentSlabs);
-    if (SlabCount > Cache->MaximumSlabs)
-        Cache->MaximumSlabs = SlabCount;
-
-    return STATUS_SUCCESS;
-
-fail4:
-    Error("fail4\n");
+            goto fail2;
 
-    while (--Index >= 0) {
-        PVOID Object = (PVOID)&Slab->Buffer[Index * Cache->Size];
+        ExInterlockedInsertTailList(&Cache->FreeList,
+                                    &Header->ListEntry,
+                                    &Cache->FreeLock);
+        InterlockedIncrement(&Cache->FreeSize);
 
-        __CacheDtor(Cache, Object);
+        InterlockedIncrement(&Cache->Count);
     }
 
-    __CacheFree(Slab->Mask);
-
-fail3:
-    Error("fail3\n");
-
-    __CacheFree(Slab);
+    return STATUS_SUCCESS;
 
 fail2:
-    Error("fail2\n");
+    __CacheFree(Header);
 
 fail1:
-    Error("fail1 (%08x)\n", status);
-
     return status;
 }
 
-// Must be called with lock held
+// Lock must be held
 static VOID
-CacheDestroySlab(
+CacheSpill(
     IN  PXENBUS_CACHE       Cache,
-    IN  PXENBUS_CACHE_SLAB  Slab
+    IN  ULONG               Target
     )
 {
-    LONG                    Index;
+    PLIST_ENTRY             ListEntry;
+    PXENBUS_CACHE_HEADER    Header;
 
-    ASSERT3U(Slab->CurrentOccupancy, ==, 0);
+    while (Cache->Count > (LONG)Target) {
 
-    ASSERT3U(Cache->Count, >=, Slab->MaximumOccupancy);
-    Cache->Count -= Slab->MaximumOccupancy;
+        ListEntry = ExInterlockedRemoveHeadList(&Cache->FreeList,
+                                                &Cache->FreeLock);
+        if (ListEntry == NULL)
+            break;
 
-    //
-    // The only reason the cursor should be pointing at this slab is
-    // if it is the only one in the list.
-    //
-    if (Cache->Cursor == &Slab->ListEntry)
-        Cache->Cursor = &Cache->SlabList;
+        ASSERT3S(Cache->FreeSize, >, 0);
+        InterlockedDecrement(&Cache->FreeSize);
 
-    RemoveEntryList(&Slab->ListEntry);
+        Header = CONTAINING_RECORD(ListEntry, XENBUS_CACHE_HEADER, ListEntry);
 
-    ASSERT(Cache->Cursor != &Cache->SlabList ||
-           IsListEmpty(&Cache->SlabList));
+        __CacheDtor(Cache, Header->Buffer);
 
-    Index = Slab->MaximumOccupancy;
-    while (--Index >= 0) {
-        PVOID Object = (PVOID)&Slab->Buffer[Index * Cache->Size];
+        __CacheFree(Header);
 
-        __CacheDtor(Cache, Object);
+        InterlockedDecrement(&Cache->Count);
     }
-
-    ASSERT(Cache->CurrentSlabs != 0);
-    InterlockedDecrement(&Cache->CurrentSlabs);
-
-    __CacheFree(Slab->Mask);
-    __CacheFree(Slab);
 }
 
-static FORCEINLINE ULONG
-__CacheMaskScan(
-    IN  ULONG   *Mask,
-    IN  ULONG   Maximum
+static PVOID
+CacheGetFromMagazine(
+    IN  PXENBUS_CACHE_MAGAZINE  Magazine
     )
 {
-    ULONG       Size;
-    ULONG       Index;
-
-    Size = P2ROUNDUP(Maximum, BITS_PER_ULONG);
-    Size /= sizeof (ULONG);
-    ASSERT(Size != 0);
+    ULONG                       Index;
 
-    for (Index = 0; Index < Size; Index++) {
-        ULONG   Free = ~Mask[Index];
-        ULONG   Bit;
+    for (Index = 0; Index < XENBUS_CACHE_MAGAZINE_SLOTS; ++Index) {
+        PVOID                   Object;
 
-        if (!_BitScanForward(&Bit, Free))
-            continue;
+        if (Magazine->Slot[Index] != NULL) {
+            Object = Magazine->Slot[Index];
+            Magazine->Slot[Index] = NULL;
 
-        Bit += Index * BITS_PER_ULONG;
-        if (Bit < Maximum)
-            return Bit;
+            return Object;
+        }
     }
 
-    return Maximum;
-}
-
-static FORCEINLINE VOID
-__CacheMaskSet(
-    IN  ULONG   *Mask,
-    IN  ULONG   Bit
-    )
-{
-    ULONG       Index = Bit / BITS_PER_ULONG;
-
-    Mask[Index] |= 1u << (Bit % BITS_PER_ULONG);
+    return NULL;
 }
 
-static FORCEINLINE BOOLEAN
-__CacheMaskTest(
-    IN  ULONG   *Mask,
-    IN  ULONG   Bit
+static NTSTATUS
+CachePutToMagazine(
+    IN  PXENBUS_CACHE_MAGAZINE  Magazine,
+    IN  PVOID                   Object
     )
 {
-    ULONG       Index = Bit / BITS_PER_ULONG;
-
-    return (Mask[Index] & (1u << (Bit % BITS_PER_ULONG))) ? TRUE : FALSE;
-}
+    ULONG                       Index;
 
-static FORCEINLINE VOID
-__CacheMaskClear(
-    IN  ULONG   *Mask,
-    IN  ULONG   Bit
-    )
-{
-    ULONG       Index = Bit / BITS_PER_ULONG;
+    for (Index = 0; Index < XENBUS_CACHE_MAGAZINE_SLOTS; ++Index) {
+        if (Magazine->Slot[Index] == NULL) {
+            Magazine->Slot[Index] = Object;
+            return STATUS_SUCCESS;
+        }
+    }
 
-    Mask[Index] &= ~(1u << (Bit % BITS_PER_ULONG));
+    return STATUS_UNSUCCESSFUL;
 }
 
-// Must be called with lock held
+// Lock must be held
 static PVOID
-CacheGetObjectFromSlab(
-    IN  PXENBUS_CACHE_SLAB  Slab
+CacheGetFromFreeList(
+    IN  PXENBUS_CACHE       Cache
     )
 {
-    PXENBUS_CACHE           Cache;
-    ULONG                   Index;
-    PVOID                   Object;
+    PLIST_ENTRY             ListEntry;
+    PXENBUS_CACHE_HEADER    Header;
+    NTSTATUS                status;
 
-    Cache = Slab->Cache;
+    ListEntry = ExInterlockedRemoveHeadList(&Cache->FreeList,
+                                            &Cache->FreeLock);
+    if (ListEntry == NULL) {
+        status = CacheFill(Cache,
+                           Cache->Count + 1);
+        if (!NT_SUCCESS(status))
+            goto fail1;
 
-    ASSERT3U(Slab->CurrentOccupancy, <=, Slab->MaximumOccupancy);
-    if (Slab->CurrentOccupancy == Slab->MaximumOccupancy)
-        return NULL;
+        ListEntry = ExInterlockedRemoveHeadList(&Cache->FreeList,
+                                                &Cache->FreeLock);
+    }
+    if (ListEntry == NULL)
+        goto fail2;
 
-    Index = __CacheMaskScan(Slab->Mask, Slab->MaximumOccupancy);
-    BUG_ON(Index >= Slab->MaximumOccupancy);
+    ASSERT3S(Cache->FreeSize, >, 0);
+    InterlockedDecrement(&Cache->FreeSize);
 
-    __CacheMaskSet(Slab->Mask, Index);
-    Slab->CurrentOccupancy++;
+    Header = CONTAINING_RECORD(ListEntry, XENBUS_CACHE_HEADER, ListEntry);
+    ASSERT3P(Header->Cache, ==, Cache);
 
-    Object = (PVOID)&Slab->Buffer[Index * Cache->Size];
-    ASSERT3U(Index, ==, (ULONG)((PUCHAR)Object - &Slab->Buffer[0]) /
-             Cache->Size);
+    return Header->Buffer;
 
-    return Object;
+fail2:
+fail1:
+    return NULL;
 }
 
-// Must be called with lock held
+// Lock must be held
 static VOID
-CachePutObjectToSlab(
-    IN  PXENBUS_CACHE_SLAB  Slab,
+CachePutToFreeList(
+    IN  PXENBUS_CACHE       Cache,
     IN  PVOID               Object
     )
 {
-    PXENBUS_CACHE           Cache;
+    PXENBUS_CACHE_HEADER    Header;
+
+    Header = CONTAINING_RECORD(Object, XENBUS_CACHE_HEADER, Buffer);
+    ASSERT3P(Header->Cache, ==, Cache);
+
+    ExInterlockedInsertTailList(&Cache->FreeList,
+                                &Header->ListEntry,
+                                &Cache->FreeLock);
+    InterlockedIncrement(&Cache->FreeSize);
+}
+
+static VOID
+__CacheFlushMagazines(
+    IN  PXENBUS_CACHE       Cache
+    )
+{
+    KIRQL                   Irql;
     ULONG                   Index;
 
-    Cache = Slab->Cache;
+    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+    __CacheAcquireLock(Cache);
 
-    Index = (ULONG)((PUCHAR)Object - &Slab->Buffer[0]) / Cache->Size;
-    BUG_ON(Index >= Slab->MaximumOccupancy);
+    for (Index = 0; Index < Cache->MagazineCount; ++Index) {
+        PXENBUS_CACHE_MAGAZINE  Magazine = &Cache->Magazines[Index];
+        PVOID                   Object;
 
-    ASSERT(Slab->CurrentOccupancy != 0);
-    --Slab->CurrentOccupancy;
+        while ((Object = CacheGetFromMagazine(Magazine)) != NULL) {
+            CachePutToFreeList(Cache, Object);
+        }
+    }
 
-    ASSERT(__CacheMaskTest(Slab->Mask, Index));
-    __CacheMaskClear(Slab->Mask, Index);
+    __CacheReleaseLock(Cache);
+    KeLowerIrql(Irql);
 }
 
 static PVOID
@@ -532,62 +348,35 @@ CacheGet(
     )
 {
     KIRQL                   Irql;
-    ULONG                   Index;
     PXENBUS_CACHE_MAGAZINE  Magazine;
     PVOID                   Object;
-    LONG                    ObjectCount;
+    ULONG                   Index;
 
     UNREFERENCED_PARAMETER(Interface);
 
+    Object = NULL;
+
     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
     Index = KeGetCurrentProcessorNumberEx(NULL);
 
     ASSERT3U(Index, <, Cache->MagazineCount);
-    Magazine = &Cache->Magazine[Index];
-
-    Object = CacheGetObjectFromMagazine(Magazine);
-    if (Object != NULL)
-        goto done;
-
-    if (!Locked)
-        __CacheAcquireLock(Cache);
-
-again:
-    if (Cache->Cursor != &Cache->SlabList) {
-        PLIST_ENTRY ListEntry = Cache->Cursor;
-        PXENBUS_CACHE_SLAB  Slab;
-
-        Slab = CONTAINING_RECORD(ListEntry, XENBUS_CACHE_SLAB, ListEntry);
-
-        Object = CacheGetObjectFromSlab(Slab);
-        ASSERT(Object != NULL);
-
-        if (Slab->CurrentOccupancy == Slab->MaximumOccupancy)
-            Cache->Cursor = Slab->ListEntry.Flink;
-    }
+    Magazine = &Cache->Magazines[Index];
 
+    Object = CacheGetFromMagazine(Magazine);
     if (Object == NULL) {
-        NTSTATUS status;
+        if (!Locked)
+            __CacheAcquireLock(Cache);
 
-        ASSERT3P(Cache->Cursor, ==, &Cache->SlabList);
+        Object = CacheGetFromFreeList(Cache);
 
-        status = CacheCreateSlab(Cache);
-        if (NT_SUCCESS(status)) {
-            ASSERT(Cache->Cursor != &Cache->SlabList);
-            goto again;
-        }
+        if (!Locked)
+            __CacheReleaseLock(Cache);
     }
 
-    CacheAudit(Cache);
-
-    if (!Locked)
-        __CacheReleaseLock(Cache);
-
-done:
     if (Object != NULL) {
-        ObjectCount = InterlockedIncrement(&Cache->CurrentObjects);
-        if (ObjectCount > Cache->MaximumObjects)
-            Cache->MaximumObjects = ObjectCount;
+        LONG    Count = InterlockedIncrement(&Cache->CurrentObjects);
+        if (Count > Cache->MaximumObjects)
+            Cache->MaximumObjects = Count;
     }
 
     KeLowerIrql(Irql);
@@ -606,7 +395,6 @@ CachePut(
     KIRQL                   Irql;
     ULONG                   Index;
     PXENBUS_CACHE_MAGAZINE  Magazine;
-    PXENBUS_CACHE_SLAB      Slab;
     NTSTATUS                status;
 
     UNREFERENCED_PARAMETER(Interface);
@@ -615,131 +403,23 @@ CachePut(
     Index = KeGetCurrentProcessorNumberEx(NULL);
 
     ASSERT3U(Index, <, Cache->MagazineCount);
-    Magazine = &Cache->Magazine[Index];
-
-    status = CachePutObjectToMagazine(Magazine, Object);
-
-    if (NT_SUCCESS(status))
-        goto done;
-
-    Slab = (PXENBUS_CACHE_SLAB)PAGE_ALIGN(Object);
-    ASSERT3U(Slab->Magic, ==, XENBUS_CACHE_SLAB_MAGIC);
+    Magazine = &Cache->Magazines[Index];
 
-    if (!Locked)
-        __CacheAcquireLock(Cache);
+    status = CachePutToMagazine(Magazine, Object);
 
-    CachePutObjectToSlab(Slab, Object);
+    if (!NT_SUCCESS(status)) {
+        if (!Locked)
+            __CacheAcquireLock(Cache);
 
-    /* Re-insert to keep slab list ordered */
-    RemoveEntryList(&Slab->ListEntry);
-    CacheInsertSlab(Cache, Slab);
-
-    CacheAudit(Cache);
-
-    if (!Locked)
-        __CacheReleaseLock(Cache);
-
-done:
-    ASSERT(Cache->CurrentObjects != 0);
-    InterlockedDecrement(&Cache->CurrentObjects);
-
-    KeLowerIrql(Irql);
-}
+        CachePutToFreeList(Cache, Object);
 
-static NTSTATUS
-CacheFill(
-    IN  PXENBUS_CACHE   Cache,
-    IN  ULONG           Count
-    )
-{
-    KIRQL               Irql;
-    NTSTATUS            status;
-
-    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
-    __CacheAcquireLock(Cache);
-
-    status = STATUS_SUCCESS;
-    while (Cache->Count < Count) {
-        status = CacheCreateSlab(Cache);
-        if (!NT_SUCCESS(status))
-            break;
+        if (!Locked)
+            __CacheReleaseLock(Cache);
     }
 
-    CacheAudit(Cache);
-
-    __CacheReleaseLock(Cache);
-    KeLowerIrql(Irql);
-
-    return status;
-}
-
-static VOID
-CacheSpill(
-    IN  PXENBUS_CACHE   Cache,
-    IN  ULONG           Count
-    )
-{
-    KIRQL               Irql;
-    PLIST_ENTRY         ListEntry;
-
-    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
-    __CacheAcquireLock(Cache);
-
-    if (Cache->Count <= Count)
-        goto done;
-
-    while (!IsListEmpty(&Cache->SlabList)) {
-        PXENBUS_CACHE_SLAB  Slab;
-
-        // Actual list removal is done in CacheDestroySlab()
-        ListEntry = Cache->SlabList.Blink;
-        ASSERT(ListEntry != &Cache->SlabList);
-
-        Slab = CONTAINING_RECORD(ListEntry, XENBUS_CACHE_SLAB, ListEntry);
-
-        if (Slab->CurrentOccupancy != 0)
-            break;
-
-        ASSERT(Cache->Count >= Slab->MaximumOccupancy);
-        if (Cache->Count - Slab->MaximumOccupancy < Count)
-            break;
-
-        CacheDestroySlab(Cache, Slab);
-    }
-
-    CacheAudit(Cache);
-
-done:
-    __CacheReleaseLock(Cache);
-    KeLowerIrql(Irql);
-}
-
-static FORCEINLINE VOID
-__CacheFlushMagazines(
-    IN  PXENBUS_CACHE   Cache
-    )
-{
-    KIRQL               Irql;
-    ULONG               Index;
-
-    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
-    __CacheAcquireLock(Cache);
-
-    for (Index = 0; Index < Cache->MagazineCount; Index++) {
-        PXENBUS_CACHE_MAGAZINE  Magazine = &Cache->Magazine[Index];
-        PVOID                   Object;
-
-        while ((Object = CacheGetObjectFromMagazine(Magazine)) != NULL) {
-            PXENBUS_CACHE_SLAB  Slab;
-
-            Slab = (PXENBUS_CACHE_SLAB)PAGE_ALIGN(Object);
-            ASSERT3U(Slab->Magic, ==, XENBUS_CACHE_SLAB_MAGIC);
-
-            CachePutObjectToSlab(Slab, Object);
-        }
-    }
+    ASSERT3U(Cache->CurrentObjects, >, 0);
+    InterlockedDecrement(&Cache->CurrentObjects);
 
-    __CacheReleaseLock(Cache);
     KeLowerIrql(Irql);
 }
 
@@ -791,8 +471,8 @@ CacheCreate(
     (*Cache)->ReleaseLock = ReleaseLock;
     (*Cache)->Argument = Argument;
 
-    InitializeListHead(&(*Cache)->SlabList);
-    (*Cache)->Cursor = &(*Cache)->SlabList;
+    InitializeListHead(&(*Cache)->FreeList);
+    KeInitializeSpinLock(&(*Cache)->FreeLock);
 
     status = STATUS_INVALID_PARAMETER;
     if ((*Cache)->Reservation > (*Cache)->Cap)
@@ -803,10 +483,10 @@ CacheCreate(
         goto fail4;
 
     (*Cache)->MagazineCount = 
KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS);
-    (*Cache)->Magazine = __CacheAllocate(sizeof (XENBUS_CACHE_MAGAZINE) * 
(*Cache)->MagazineCount);
+    (*Cache)->Magazines = __CacheAllocate(sizeof (XENBUS_CACHE_MAGAZINE) * 
(*Cache)->MagazineCount);
 
     status = STATUS_NO_MEMORY;
-    if ((*Cache)->Magazine == NULL)
+    if ((*Cache)->Magazines == NULL)
         goto fail5;
 
     KeAcquireSpinLock(&Context->Lock, &Irql);
@@ -830,9 +510,9 @@ fail4:
 fail3:
     Error("fail3\n");
 
-    (*Cache)->Cursor = NULL;
-    ASSERT(IsListEmpty(&(*Cache)->SlabList));
-    RtlZeroMemory(&(*Cache)->SlabList, sizeof (LIST_ENTRY));
+    ASSERT(IsListEmpty(&(*Cache)->FreeList));
+    RtlZeroMemory(&(*Cache)->FreeList, sizeof (LIST_ENTRY));
+    RtlZeroMemory(&(*Cache)->FreeLock, sizeof (KSPIN_LOCK));
 
     (*Cache)->Argument = NULL;
     (*Cache)->ReleaseLock = NULL;
@@ -903,22 +583,22 @@ CacheDestroy(
 
     __CacheFlushMagazines(Cache);
 
-    ASSERT(IsZeroMemory(Cache->Magazine, sizeof (XENBUS_CACHE_MAGAZINE) * 
Cache->MagazineCount));
-    __CacheFree(Cache->Magazine);
-    Cache->Magazine = NULL;
+    ASSERT(IsZeroMemory(Cache->Magazines, sizeof (XENBUS_CACHE_MAGAZINE) * 
Cache->MagazineCount));
+    __CacheFree(Cache->Magazines);
+    Cache->Magazines = NULL;
     Cache->MagazineCount = 0;
 
     CacheSpill(Cache, 0);
 
-    ASSERT(Cache->CurrentObjects == 0);
+    ASSERT3S(Cache->Count, ==, 0);
+    ASSERT3S(Cache->CurrentObjects, ==, 0);
     Cache->MaximumObjects = 0;
 
-    ASSERT(Cache->CurrentSlabs == 0);
-    Cache->MaximumSlabs = 0;
+    ASSERT(IsListEmpty(&Cache->FreeList));
+    ASSERT(Cache->FreeSize == 0);
 
-    Cache->Cursor = NULL;
-    ASSERT(IsListEmpty(&Cache->SlabList));
-    RtlZeroMemory(&Cache->SlabList, sizeof (LIST_ENTRY));
+    RtlZeroMemory(&Cache->FreeList, sizeof (LIST_ENTRY));
+    RtlZeroMemory(&Cache->FreeLock, sizeof (KSPIN_LOCK));
 
     Cache->Argument = NULL;
     Cache->ReleaseLock = NULL;
@@ -963,14 +643,13 @@ CacheDebugCallback(
 
             XENBUS_DEBUG(Printf,
                          &Context->DebugInterface,
-                         "- %s: Count = %d, Reservation = %d, Objects = %d / 
%d, Slabs = %d / %d\n",
+                         "- %s: Reservation = %d, Cap = %d, Count = %d, 
Objects = %d / %d\n",
                          Cache->Name,
-                         Cache->Count,
                          Cache->Reservation,
+                         Cache->Cap,
+                         Cache->Count,
                          Cache->CurrentObjects,
-                         Cache->MaximumObjects,
-                         Cache->CurrentSlabs,
-                         Cache->MaximumSlabs);
+                         Cache->MaximumObjects);
         }
     }
 }
@@ -1024,11 +703,14 @@ CacheMonitor(
 
             Cache = CONTAINING_RECORD(ListEntry, XENBUS_CACHE, ListEntry);
 
-            if (Cache->Count < Cache->Reservation)
-                CacheFill(Cache, Cache->Reservation);
-            else if (Cache->Count > Cache->Reservation)
+            if (Cache->Count < (LONG)Cache->Reservation) {
+                CacheFill(Cache,
+                          Cache->Reservation);
+            } else if (Cache->Count > (LONG)Cache->Reservation) {
                 CacheSpill(Cache,
-                           __max(Cache->Reservation, (Cache->Count / 2)));
+                           __max((LONG)Cache->Reservation,
+                                 (Cache->Count / 2)));
+            }
         }
 
 loop:
-- 
2.32.0.windows.1




 


Rackspace

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