Discussion:
[win-pv-devel] [PATCH] Add a Cap parameter to the XENBUS_CACHE Create method
Paul Durrant
2018-10-30 09:44:19 UTC
Permalink
There is currently no parameter to prevent a single cache from growing to
consume all available kernel memory. This patch adds such a parameter and
also adjusts the XENBUS_GNTTAB CreateCache method to take a similar
parameter.

These will allow client drivers to place limits on their caches to avoid,
for example, XENVBD starving XENVIF of grant table space.

Signed-off-by: Paul Durrant <***@citrix.com>
---
include/cache_interface.h | 34 ++++++++++++++-
include/gnttab_interface.h | 39 +++++++++++++++--
include/revision.h | 3 +-
src/xenbus/cache.c | 105 +++++++++++++++++++++++++++++++++++++++------
src/xenbus/gnttab.c | 58 ++++++++++++++++++++++++-
5 files changed, 218 insertions(+), 21 deletions(-)

diff --git a/include/cache_interface.h b/include/cache_interface.h
index dae3ac6..ce50f4e 100644
--- a/include/cache_interface.h
+++ b/include/cache_interface.h
@@ -123,6 +123,20 @@ typedef VOID
IN PVOID Argument
);

+typedef NTSTATUS
+(*XENBUS_CACHE_CREATE_V1)(
+ IN PINTERFACE Interface,
+ IN const CHAR *Name,
+ IN ULONG Size,
+ IN ULONG Reservation,
+ IN XENBUS_CACHE_CTOR Ctor,
+ IN XENBUS_CACHE_DTOR Dtor,
+ IN XENBUS_CACHE_ACQUIRE_LOCK AcquireLock,
+ IN XENBUS_CACHE_RELEASE_LOCK ReleaseLock,
+ IN PVOID Argument OPTIONAL,
+ OUT PXENBUS_CACHE *Cache
+ );
+
/*! \typedef XENBUS_CACHE_CREATE
\brief Create a cache of objects of the given \a Size

@@ -130,6 +144,7 @@ typedef VOID
\param Name A name for the cache which will be used in debug output
\param Size The size of each object in bytes
\param Reservation The target minimum population of the cache
+ \param Cap The maximum population of the cache
\param Ctor A callback which is invoked when a new object created
\param Dtor A callback which is invoked when an object is destroyed
\param AcquireLock A callback invoked to acquire a spinlock
@@ -146,6 +161,7 @@ typedef NTSTATUS
IN const CHAR *Name,
IN ULONG Size,
IN ULONG Reservation,
+ IN ULONG Cap,
IN XENBUS_CACHE_CTOR Ctor,
IN XENBUS_CACHE_DTOR Dtor,
IN XENBUS_CACHE_ACQUIRE_LOCK AcquireLock,
@@ -211,13 +227,27 @@ struct _XENBUS_CACHE_INTERFACE_V1 {
INTERFACE Interface;
XENBUS_CACHE_ACQUIRE CacheAcquire;
XENBUS_CACHE_RELEASE CacheRelease;
+ XENBUS_CACHE_CREATE_V1 CacheCreateVersion1;
+ XENBUS_CACHE_GET CacheGet;
+ XENBUS_CACHE_PUT CachePut;
+ XENBUS_CACHE_DESTROY CacheDestroy;
+};
+
+/*! \struct _XENBUS_CACHE_INTERFACE_V2
+ \brief CACHE interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_CACHE_INTERFACE_V2 {
+ INTERFACE Interface;
+ XENBUS_CACHE_ACQUIRE CacheAcquire;
+ XENBUS_CACHE_RELEASE CacheRelease;
XENBUS_CACHE_CREATE CacheCreate;
XENBUS_CACHE_GET CacheGet;
XENBUS_CACHE_PUT CachePut;
XENBUS_CACHE_DESTROY CacheDestroy;
};

-typedef struct _XENBUS_CACHE_INTERFACE_V1 XENBUS_CACHE_INTERFACE, *PXENBUS_CACHE_INTERFACE;
+typedef struct _XENBUS_CACHE_INTERFACE_V2 XENBUS_CACHE_INTERFACE, *PXENBUS_CACHE_INTERFACE;

/*! \def XENBUS_CACHE
\brief Macro at assist in method invocation
@@ -228,6 +258,6 @@ typedef struct _XENBUS_CACHE_INTERFACE_V1 XENBUS_CACHE_INTERFACE, *PXENBUS_CACHE
#endif // _WINDLL

#define XENBUS_CACHE_INTERFACE_VERSION_MIN 1
-#define XENBUS_CACHE_INTERFACE_VERSION_MAX 1
+#define XENBUS_CACHE_INTERFACE_VERSION_MAX 2

#endif // _XENBUS_CACHE_INTERFACE_H
diff --git a/include/gnttab_interface.h b/include/gnttab_interface.h
index 61272ab..c34dbd0 100644
--- a/include/gnttab_interface.h
+++ b/include/gnttab_interface.h
@@ -72,12 +72,24 @@ typedef VOID
IN PINTERFACE Interface
);

+typedef NTSTATUS
+(*XENBUS_GNTTAB_CREATE_CACHE_V1)(
+ IN PINTERFACE Interface,
+ IN const CHAR *Name,
+ IN ULONG Reservation,
+ IN XENBUS_CACHE_ACQUIRE_LOCK AcquireLock,
+ IN XENBUS_CACHE_RELEASE_LOCK ReleaseLock,
+ IN PVOID Argument OPTIONAL,
+ OUT PXENBUS_GNTTAB_CACHE *Cache
+ );
+
/*! \typedef XENBUS_GNTTAB_CREATE_CACHE
\brief Create a cache of grant table entries

\param Interface The interface header
\param Name A name for the cache which will be used in debug output
\param Reservation The target minimum population of the cache
+ \param Cap The maximum population of the cache
\param AcquireLock A callback invoked to acquire a spinlock
\param ReleaseLock A callback invoked to release the spinlock
\param Argument An optional context argument passed to the callbacks
@@ -88,6 +100,7 @@ typedef NTSTATUS
IN PINTERFACE Interface,
IN const CHAR *Name,
IN ULONG Reservation,
+ IN ULONG Cap,
IN XENBUS_CACHE_ACQUIRE_LOCK AcquireLock,
IN XENBUS_CACHE_RELEASE_LOCK ReleaseLock,
IN PVOID Argument OPTIONAL,
@@ -228,7 +241,7 @@ struct _XENBUS_GNTTAB_INTERFACE_V1 {
INTERFACE Interface;
XENBUS_GNTTAB_ACQUIRE GnttabAcquire;
XENBUS_GNTTAB_RELEASE GnttabRelease;
- XENBUS_GNTTAB_CREATE_CACHE GnttabCreateCache;
+ XENBUS_GNTTAB_CREATE_CACHE_V1 GnttabCreateCacheVersion1;
XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS GnttabPermitForeignAccess;
XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS GnttabRevokeForeignAccess;
XENBUS_GNTTAB_GET_REFERENCE GnttabGetReference;
@@ -243,7 +256,7 @@ struct _XENBUS_GNTTAB_INTERFACE_V2 {
INTERFACE Interface;
XENBUS_GNTTAB_ACQUIRE GnttabAcquire;
XENBUS_GNTTAB_RELEASE GnttabRelease;
- XENBUS_GNTTAB_CREATE_CACHE GnttabCreateCache;
+ XENBUS_GNTTAB_CREATE_CACHE_V1 GnttabCreateCacheVersion1;
XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS GnttabPermitForeignAccess;
XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS GnttabRevokeForeignAccess;
XENBUS_GNTTAB_GET_REFERENCE GnttabGetReference;
@@ -260,6 +273,24 @@ struct _XENBUS_GNTTAB_INTERFACE_V3 {
INTERFACE Interface;
XENBUS_GNTTAB_ACQUIRE GnttabAcquire;
XENBUS_GNTTAB_RELEASE GnttabRelease;
+ XENBUS_GNTTAB_CREATE_CACHE_V1 GnttabCreateCacheVersion1;
+ XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS GnttabPermitForeignAccess;
+ XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS GnttabRevokeForeignAccess;
+ XENBUS_GNTTAB_GET_REFERENCE GnttabGetReference;
+ XENBUS_GNTTAB_QUERY_REFERENCE GnttabQueryReference;
+ XENBUS_GNTTAB_DESTROY_CACHE GnttabDestroyCache;
+ XENBUS_GNTTAB_MAP_FOREIGN_PAGES GnttabMapForeignPages;
+ XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES GnttabUnmapForeignPages;
+};
+
+/*! \struct _XENBUS_GNTTAB_INTERFACE_V4
+ \brief GNTTAB interface version 4
+ \ingroup interfaces
+*/
+struct _XENBUS_GNTTAB_INTERFACE_V4 {
+ INTERFACE Interface;
+ XENBUS_GNTTAB_ACQUIRE GnttabAcquire;
+ XENBUS_GNTTAB_RELEASE GnttabRelease;
XENBUS_GNTTAB_CREATE_CACHE GnttabCreateCache;
XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS GnttabPermitForeignAccess;
XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS GnttabRevokeForeignAccess;
@@ -270,7 +301,7 @@ struct _XENBUS_GNTTAB_INTERFACE_V3 {
XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES GnttabUnmapForeignPages;
};

-typedef struct _XENBUS_GNTTAB_INTERFACE_V3 XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNTTAB_INTERFACE;
+typedef struct _XENBUS_GNTTAB_INTERFACE_V4 XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNTTAB_INTERFACE;

/*! \def XENBUS_GNTTAB
\brief Macro at assist in method invocation
@@ -281,7 +312,7 @@ typedef struct _XENBUS_GNTTAB_INTERFACE_V3 XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNT
#endif // _WINDLL

#define XENBUS_GNTTAB_INTERFACE_VERSION_MIN 1
-#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 3
+#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 4

#endif // _XENBUS_GNTTAB_INTERFACE_H

diff --git a/include/revision.h b/include/revision.h
index ea489f5..28ee461 100644
--- a/include/revision.h
+++ b/include/revision.h
@@ -54,6 +54,7 @@
DEFINE_REVISION(0x09000001, 1, 2, 6, 1, 2, 1, 1, 2, 1, 1, 1), \
DEFINE_REVISION(0x09000002, 1, 2, 7, 1, 2, 1, 1, 2, 1, 1, 1), \
DEFINE_REVISION(0x09000003, 1, 2, 8, 1, 2, 1, 1, 2, 1, 1, 1), \
- DEFINE_REVISION(0x09000004, 1, 2, 8, 1, 2, 1, 1, 3, 1, 1, 1)
+ DEFINE_REVISION(0x09000004, 1, 2, 8, 1, 2, 1, 1, 3, 1, 1, 1), \
+ DEFINE_REVISION(0x09000005, 1, 2, 8, 1, 2, 1, 2, 4, 1, 1, 1)

#endif // _REVISION_H
diff --git a/src/xenbus/cache.c b/src/xenbus/cache.c
index 68bfb39..a0f4135 100644
--- a/src/xenbus/cache.c
+++ b/src/xenbus/cache.c
@@ -76,6 +76,7 @@ struct _XENBUS_CACHE {
CHAR Name[MAXNAMELEN];
ULONG Size;
ULONG Reservation;
+ ULONG Cap;
NTSTATUS (*Ctor)(PVOID, PVOID);
VOID (*Dtor)(PVOID, PVOID);
VOID (*AcquireLock)(PVOID);
@@ -234,6 +235,7 @@ CacheCreateSlab(
{
PXENBUS_CACHE_SLAB Slab;
ULONG NumberOfBytes;
+ ULONG Count;
LARGE_INTEGER LowAddress;
LARGE_INTEGER HighAddress;
LARGE_INTEGER Boundary;
@@ -243,6 +245,13 @@ CacheCreateSlab(
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;

LowAddress.QuadPart = 0ull;
HighAddress.QuadPart = ~0ull;
@@ -257,31 +266,30 @@ CacheCreateSlab(

status = STATUS_NO_MEMORY;
if (Slab == NULL)
- goto fail1;
+ goto fail2;

RtlZeroMemory(Slab, NumberOfBytes);

Slab->Magic = XENBUS_CACHE_SLAB_MAGIC;
Slab->Cache = Cache;
- Slab->Count = (NumberOfBytes -
- FIELD_OFFSET(XENBUS_CACHE_SLAB, Buffer)) /
- Cache->Size;
- ASSERT(Slab->Count != 0);
+ Slab->Count = Count;

for (Index = 0; Index < (LONG)Slab->Count; Index++) {
PVOID Object = (PVOID)&Slab->Buffer[Index * Cache->Size];

status = __CacheCtor(Cache, Object);
if (!NT_SUCCESS(status))
- goto fail2;
+ goto fail3;
}

CacheInsertSlab(Cache, Slab);
- Cache->Count += Slab->Count;
+ Cache->Count += Count;

return Slab;

-fail2:
+fail3:
+ Error("fail3\n");
+
while (--Index >= 0) {
PVOID Object = (PVOID)&Slab->Buffer[Index * Cache->Size];

@@ -290,6 +298,9 @@ fail2:

MmFreeContiguousMemory(Slab);

+fail2:
+ Error("fail2\n");
+
fail1:
Error("fail1 (%08x)\n", status);

@@ -566,6 +577,7 @@ CacheCreate(
IN const CHAR *Name,
IN ULONG Size,
IN ULONG Reservation,
+ IN ULONG Cap,
IN NTSTATUS (*Ctor)(PVOID, PVOID),
IN VOID (*Dtor)(PVOID, PVOID),
IN VOID (*AcquireLock)(PVOID),
@@ -596,8 +608,12 @@ CacheCreate(
Size = __max(Size, MINIMUM_OBJECT_SIZE);
Size = P2ROUNDUP(Size, sizeof (ULONG_PTR));

+ if (Cap == 0)
+ Cap = ULONG_MAX;
+
(*Cache)->Size = Size;
(*Cache)->Reservation = Reservation;
+ (*Cache)->Cap = Cap;
(*Cache)->Ctor = Ctor;
(*Cache)->Dtor = Dtor;
(*Cache)->AcquireLock = AcquireLock;
@@ -606,10 +622,14 @@ CacheCreate(

InitializeListHead(&(*Cache)->SlabList);

+ status = STATUS_INVALID_PARAMETER;
+ if ((*Cache)->Reservation > (*Cache)->Cap)
+ goto fail3;
+
if ((*Cache)->Reservation != 0) {
status = __CacheFill(*Cache);
if (!NT_SUCCESS(status))
- goto fail3;
+ goto fail4;
}

(*Cache)->MagazineCount = KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS);
@@ -617,7 +637,7 @@ CacheCreate(

status = STATUS_NO_MEMORY;
if ((*Cache)->Magazine == NULL)
- goto fail4;
+ goto fail5;

KeAcquireSpinLock(&Context->Lock, &Irql);
InsertTailList(&Context->List, &(*Cache)->ListEntry);
@@ -627,13 +647,16 @@ CacheCreate(

return STATUS_SUCCESS;

-fail4:
- Error("fail4\n");
+fail5:
+ Error("fail5\n");

(*Cache)->MagazineCount = 0;

__CacheEmpty(*Cache);

+fail4:
+ Error("fail4\n");
+
fail3:
Error("fail3\n");

@@ -645,6 +668,8 @@ fail3:
(*Cache)->AcquireLock = NULL;
(*Cache)->Dtor = NULL;
(*Cache)->Ctor = NULL;
+ (*Cache)->Cap = 0;
+ (*Cache)->Reservation = 0;
(*Cache)->Size = 0;

fail2:
@@ -661,6 +686,33 @@ fail1:
return status;
}

+static NTSTATUS
+CacheCreateVersion1(
+ IN PINTERFACE Interface,
+ IN const CHAR *Name,
+ IN ULONG Size,
+ IN ULONG Reservation,
+ IN NTSTATUS (*Ctor)(PVOID, PVOID),
+ IN VOID (*Dtor)(PVOID, PVOID),
+ IN VOID (*AcquireLock)(PVOID),
+ IN VOID (*ReleaseLock)(PVOID),
+ IN PVOID Argument,
+ OUT PXENBUS_CACHE *Cache
+ )
+{
+ return CacheCreate(Interface,
+ Name,
+ Size,
+ Reservation,
+ 0,
+ Ctor,
+ Dtor,
+ AcquireLock,
+ ReleaseLock,
+ Argument,
+ Cache);
+}
+
static VOID
CacheDestroy(
IN PINTERFACE Interface,
@@ -696,6 +748,8 @@ CacheDestroy(
Cache->AcquireLock = NULL;
Cache->Dtor = NULL;
Cache->Ctor = NULL;
+ Cache->Cap = 0;
+ Cache->Reservation = 0;
Cache->Size = 0;

RtlZeroMemory(Cache->Name, sizeof (Cache->Name));
@@ -826,6 +880,16 @@ static struct _XENBUS_CACHE_INTERFACE_V1 CacheInterfaceVersion1 = {
{ sizeof (struct _XENBUS_CACHE_INTERFACE_V1), 1, NULL, NULL, NULL },
CacheAcquire,
CacheRelease,
+ CacheCreateVersion1,
+ CacheGet,
+ CachePut,
+ CacheDestroy
+};
+
+static struct _XENBUS_CACHE_INTERFACE_V2 CacheInterfaceVersion2 = {
+ { sizeof (struct _XENBUS_CACHE_INTERFACE_V2), 2, NULL, NULL, NULL },
+ CacheAcquire,
+ CacheRelease,
CacheCreate,
CacheGet,
CachePut,
@@ -900,6 +964,23 @@ CacheGetInterface(
status = STATUS_SUCCESS;
break;
}
+ case 2: {
+ struct _XENBUS_CACHE_INTERFACE_V2 *CacheInterface;
+
+ CacheInterface = (struct _XENBUS_CACHE_INTERFACE_V2 *)Interface;
+
+ status = STATUS_BUFFER_OVERFLOW;
+ if (Size < sizeof (struct _XENBUS_CACHE_INTERFACE_V2))
+ break;
+
+ *CacheInterface = CacheInterfaceVersion2;
+
+ ASSERT3U(Interface->Version, ==, Version);
+ Interface->Context = Context;
+
+ status = STATUS_SUCCESS;
+ break;
+ }
default:
status = STATUS_NOT_SUPPORTED;
break;
diff --git a/src/xenbus/gnttab.c b/src/xenbus/gnttab.c
index ca60a48..e590a5c 100644
--- a/src/xenbus/gnttab.c
+++ b/src/xenbus/gnttab.c
@@ -327,6 +327,7 @@ GnttabCreateCache(
IN PINTERFACE Interface,
IN const CHAR *Name,
IN ULONG Reservation,
+ IN ULONG Cap,
IN VOID (*AcquireLock)(PVOID),
IN VOID (*ReleaseLock)(PVOID),
IN PVOID Argument,
@@ -361,6 +362,7 @@ GnttabCreateCache(
(*Cache)->Name,
sizeof (XENBUS_GNTTAB_ENTRY),
Reservation,
+ Cap,
GnttabEntryCtor,
GnttabEntryDtor,
GnttabAcquireLock,
@@ -399,6 +401,27 @@ fail1:
return status;
}

+static NTSTATUS
+GnttabCreateCacheVersion1(
+ IN PINTERFACE Interface,
+ IN const CHAR *Name,
+ IN ULONG Reservation,
+ IN VOID (*AcquireLock)(PVOID),
+ IN VOID (*ReleaseLock)(PVOID),
+ IN PVOID Argument,
+ OUT PXENBUS_GNTTAB_CACHE *Cache
+ )
+{
+ return GnttabCreateCache(Interface,
+ Name,
+ Reservation,
+ 0,
+ AcquireLock,
+ ReleaseLock,
+ Argument,
+ Cache);
+}
+
static VOID
GnttabDestroyCache(
IN PINTERFACE Interface,
@@ -960,7 +983,7 @@ static struct _XENBUS_GNTTAB_INTERFACE_V1 GnttabInterfaceVersion1 = {
{ sizeof (struct _XENBUS_GNTTAB_INTERFACE_V1), 1, NULL, NULL, NULL },
GnttabAcquire,
GnttabRelease,
- GnttabCreateCache,
+ GnttabCreateCacheVersion1,
GnttabPermitForeignAccess,
GnttabRevokeForeignAccess,
GnttabGetReference,
@@ -971,7 +994,7 @@ static struct _XENBUS_GNTTAB_INTERFACE_V2 GnttabInterfaceVersion2 = {
{ sizeof (struct _XENBUS_GNTTAB_INTERFACE_V2), 2, NULL, NULL, NULL },
GnttabAcquire,
GnttabRelease,
- GnttabCreateCache,
+ GnttabCreateCacheVersion1,
GnttabPermitForeignAccess,
GnttabRevokeForeignAccess,
GnttabGetReference,
@@ -984,6 +1007,20 @@ static struct _XENBUS_GNTTAB_INTERFACE_V3 GnttabInterfaceVersion3 = {
{ sizeof (struct _XENBUS_GNTTAB_INTERFACE_V3), 3, NULL, NULL, NULL },
GnttabAcquire,
GnttabRelease,
+ GnttabCreateCacheVersion1,
+ GnttabPermitForeignAccess,
+ GnttabRevokeForeignAccess,
+ GnttabGetReference,
+ GnttabQueryReference,
+ GnttabDestroyCache,
+ GnttabMapForeignPages,
+ GnttabUnmapForeignPages
+};
+
+static struct _XENBUS_GNTTAB_INTERFACE_V4 GnttabInterfaceVersion4 = {
+ { sizeof (struct _XENBUS_GNTTAB_INTERFACE_V4), 4, NULL, NULL, NULL },
+ GnttabAcquire,
+ GnttabRelease,
GnttabCreateCache,
GnttabPermitForeignAccess,
GnttabRevokeForeignAccess,
@@ -1124,6 +1161,23 @@ GnttabGetInterface(
status = STATUS_SUCCESS;
break;
}
+ case 4: {
+ struct _XENBUS_GNTTAB_INTERFACE_V4 *GnttabInterface;
+
+ GnttabInterface = (struct _XENBUS_GNTTAB_INTERFACE_V4 *)Interface;
+
+ status = STATUS_BUFFER_OVERFLOW;
+ if (Size < sizeof (struct _XENBUS_GNTTAB_INTERFACE_V4))
+ break;
+
+ *GnttabInterface = GnttabInterfaceVersion4;
+
+ ASSERT3U(Interface->Version, ==, Version);
+ Interface->Context = Context;
+
+ status = STATUS_SUCCESS;
+ break;
+ }
default:
status = STATUS_NOT_SUPPORTED;
break;
--
2.5.3
Loading...