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

[win-pv-devel] [PATCH] Don't free memory at HIGH IRQL



The hash table remove function is invoked by the EVTCHN early callback on
resume from suspend. This means it is invoked at HIGH level with interrupts
disabled, which means that memory can neither be allocated nor freed. The
code, however, does indeed free a data structure and this may well lead
to memory corruption. This patch addresses the issue by deferring freeing
the memory to a subsequently scheduled DPC.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 src/xenbus/hash_table.c | 88 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 82 insertions(+), 6 deletions(-)

diff --git a/src/xenbus/hash_table.c b/src/xenbus/hash_table.c
index 75206e4..e9ed991 100644
--- a/src/xenbus/hash_table.c
+++ b/src/xenbus/hash_table.c
@@ -54,6 +54,8 @@ typedef struct _XENBUS_HASH_TABLE_BUCKET {
 
 struct _XENBUS_HASH_TABLE {
     XENBUS_HASH_TABLE_BUCKET    Bucket[XENBUS_HASH_TABLE_NR_BUCKETS];
+    XENBUS_HASH_TABLE_BUCKET    Hidden;
+    KDPC                        Dpc;
 };
 
 #define XENBUS_HASH_TABLE_TAG   'HSAH'
@@ -240,12 +242,14 @@ HashTableRemove(
     )
 {
     PXENBUS_HASH_TABLE_BUCKET   Bucket;
+    PXENBUS_HASH_TABLE_BUCKET   Hidden;
     PLIST_ENTRY                 ListEntry;
     PXENBUS_HASH_TABLE_NODE     Node;
     KIRQL                       Irql;
     NTSTATUS                    status;
 
     Bucket = &Table->Bucket[HashTableHash(Key)];
+    Hidden = &Table->Hidden;
     
     HashTableBucketLock(Bucket, TRUE, &Irql);
 
@@ -268,7 +272,11 @@ found:
 
     HashTableBucketUnlock(Bucket, TRUE, Irql);
 
-    __HashTableFree(Node);
+    HashTableBucketLock(Hidden, TRUE, &Irql);
+    InsertTailList(&Hidden->List, &Node->ListEntry);
+    HashTableBucketUnlock(Hidden, TRUE, Irql);
+
+    KeInsertQueueDpc(&Table->Dpc, NULL, NULL);
 
     return STATUS_SUCCESS;
 
@@ -322,13 +330,64 @@ fail1:
     return status;
 }
 
+static
+_Function_class_(KDEFERRED_ROUTINE)
+_IRQL_requires_max_(DISPATCH_LEVEL)
+_IRQL_requires_min_(DISPATCH_LEVEL)
+_IRQL_requires_(DISPATCH_LEVEL)
+_IRQL_requires_same_
+VOID
+HashTableDpc(
+    IN  PKDPC                   Dpc,
+    IN  PVOID                   Context,
+    IN  PVOID                   Argument1,
+    IN  PVOID                   Argument2
+    )
+{
+    PXENBUS_HASH_TABLE          Table = Context;
+    LIST_ENTRY                  List;
+    PXENBUS_HASH_TABLE_BUCKET   Hidden;
+    KIRQL                       Irql;
+
+    UNREFERENCED_PARAMETER(Dpc);
+    UNREFERENCED_PARAMETER(Argument1);
+    UNREFERENCED_PARAMETER(Argument2);
+
+    InitializeListHead(&List);
+
+    Hidden = &Table->Hidden;
+
+    HashTableBucketLock(Hidden, TRUE, &Irql);
+
+    while (!IsListEmpty(&Hidden->List)) {
+        PLIST_ENTRY ListEntry;
+
+        ListEntry = RemoveHeadList(&Hidden->List);
+
+        InsertTailList(&List, ListEntry);
+    }
+
+    HashTableBucketUnlock(Hidden, TRUE, Irql);
+
+    while (!IsListEmpty(&List)) {
+        PLIST_ENTRY             ListEntry;
+        PXENBUS_HASH_TABLE_NODE Node;
+
+        ListEntry = RemoveHeadList(&List);
+
+        Node = CONTAINING_RECORD(ListEntry, XENBUS_HASH_TABLE_NODE, ListEntry);
+        __HashTableFree(Node);
+    }
+}
+
 NTSTATUS
 HashTableCreate(
-    OUT PXENBUS_HASH_TABLE  *Table
+    OUT PXENBUS_HASH_TABLE      *Table
     )
 {
-    ULONG                   Index;
-    NTSTATUS                status;
+    ULONG                       Index;
+    PXENBUS_HASH_TABLE_BUCKET   Hidden;
+    NTSTATUS                    status;
 
     *Table = __HashTableAllocate(sizeof (XENBUS_HASH_TABLE));
 
@@ -342,6 +401,12 @@ HashTableCreate(
         InitializeListHead(&Bucket->List);
     }
 
+    Hidden = &(*Table)->Hidden;
+
+    InitializeListHead(&Hidden->List);
+
+    KeInitializeDpc(&(*Table)->Dpc, HashTableDpc, *Table);
+
     return STATUS_SUCCESS;
 
 fail1:
@@ -352,10 +417,21 @@ fail1:
 
 VOID
 HashTableDestroy(
-    IN  PXENBUS_HASH_TABLE  Table
+    IN  PXENBUS_HASH_TABLE      Table
     )
 {
-    ULONG                   Index;
+    ULONG                       Index;
+    PXENBUS_HASH_TABLE_BUCKET   Hidden;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+    KeFlushQueuedDpcs();
+
+    RtlZeroMemory(&Table->Dpc, sizeof (KDPC));
+
+    Hidden = &Table->Hidden;
+
+    ASSERT(IsListEmpty(&Hidden->List));
+    RtlZeroMemory(&Hidden->List, sizeof (LIST_ENTRY));
 
     for (Index = 0; Index < XENBUS_HASH_TABLE_NR_BUCKETS; Index++) {
         PXENBUS_HASH_TABLE_BUCKET   Bucket = &Table->Bucket[Index];
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel

 


Rackspace

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