[ovs-dev] [PATCH v5] datapath-windows: Hot add CPU support.

Sorin Vinturis svinturis at cloudbasesolutions.com
Thu Apr 7 11:21:12 UTC 2016


Hot add CPU is the ability to dynamically add CPUs to a running
system. Adding CPUs can occur physically by adding new hardware,
logically by online hardware partitioning, or virtually through
a virtualization layer.

This patch add support to reallocate any per-cpu resources, in
case a new processor is added.

Signed-off-by: Sorin Vinturis <svinturis at cloudbasesolutions.com>
Reported-by: Sorin Vinturis <svinturis at cloudbasesolutions.com>
Reported-at: https://github.com/openvswitch/ovs-issues/issues/112
Acked-by: Paul-Daniel Boca <pboca at cloudbasesolutions.com>
---
v2: Correctly reallocate per-cpu data structures when a new processor
    is about to be added to the system.
v4: Per-cpu variables are allocated for the maximum number of processors
    supported by the system.
v5: OvsCleanup is performed after deregistering filter driver from NDIS.
    Added acked.
---
 datapath-windows/ovsext/Datapath.c |  13 +++--
 datapath-windows/ovsext/Datapath.h |   2 +-
 datapath-windows/ovsext/Driver.c   |  11 ++--
 datapath-windows/ovsext/Recirc.c   | 100 ++++++++++++++++---------------------
 datapath-windows/ovsext/Recirc.h   |  45 +++--------------
 datapath-windows/ovsext/Util.c     |  34 ++++++++++++-
 datapath-windows/ovsext/Util.h     |  20 +++++++-
 7 files changed, 117 insertions(+), 108 deletions(-)

diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index 464fa97..8c0c246 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -379,26 +379,29 @@ FreeUserDumpState(POVS_OPEN_INSTANCE instance)
     }
 }
 
-VOID
+NDIS_STATUS
 OvsInit()
 {
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
     gOvsCtrlLock = &ovsCtrlLockObj;
     NdisAllocateSpinLock(gOvsCtrlLock);
     OvsInitEventQueue();
-    OvsDeferredActionsQueueAlloc();
-    OvsDeferredActionsLevelAlloc();
+
+    status = OvsPerCpuDataInit();
+
+    return status;
 }
 
 VOID
 OvsCleanup()
 {
+    OvsPerCpuDataCleanup();
     OvsCleanupEventQueue();
     if (gOvsCtrlLock) {
         NdisFreeSpinLock(gOvsCtrlLock);
         gOvsCtrlLock = NULL;
     }
-    OvsDeferredActionsQueueFree();
-    OvsDeferredActionsLevelFree();
 }
 
 VOID
diff --git a/datapath-windows/ovsext/Datapath.h b/datapath-windows/ovsext/Datapath.h
index 2c61d82..09e233f 100644
--- a/datapath-windows/ovsext/Datapath.h
+++ b/datapath-windows/ovsext/Datapath.h
@@ -65,7 +65,7 @@ typedef struct _OVS_OPEN_INSTANCE {
 
 NDIS_STATUS OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle);
 VOID OvsDeleteDeviceObject();
-VOID OvsInit();
+NDIS_STATUS OvsInit();
 VOID OvsCleanup();
 
 POVS_OPEN_INSTANCE OvsGetOpenInstance(PFILE_OBJECT fileObject,
diff --git a/datapath-windows/ovsext/Driver.c b/datapath-windows/ovsext/Driver.c
index 853886e..80979ea 100644
--- a/datapath-windows/ovsext/Driver.c
+++ b/datapath-windows/ovsext/Driver.c
@@ -96,7 +96,10 @@ DriverEntry(PDRIVER_OBJECT driverObject,
     UNREFERENCED_PARAMETER(registryPath);
 
     /* Initialize driver associated data structures. */
-    OvsInit();
+    status = OvsInit();
+    if (status != NDIS_STATUS_SUCCESS) {
+        goto cleanup;
+    }
 
     gOvsExtDriverObject = driverObject;
 
@@ -175,12 +178,12 @@ OvsExtUnload(struct _DRIVER_OBJECT *driverObject)
 {
     UNREFERENCED_PARAMETER(driverObject);
 
-    /* Release driver associated data structures. */
-    OvsCleanup();
-
     OvsDeleteDeviceObject();
 
     NdisFDeregisterFilterDriver(gOvsExtDriverHandle);
+
+    /* Release driver associated data structures. */
+    OvsCleanup();
 }
 
 
diff --git a/datapath-windows/ovsext/Recirc.c b/datapath-windows/ovsext/Recirc.c
index 86e6f51..2febf06 100644
--- a/datapath-windows/ovsext/Recirc.c
+++ b/datapath-windows/ovsext/Recirc.c
@@ -18,71 +18,61 @@
 #include "Flow.h"
 #include "Jhash.h"
 
-static POVS_DEFERRED_ACTION_QUEUE ovsDeferredActionQueue = NULL;
-static UINT32* ovsDeferredActionLevel = NULL;
-
 /*
  * --------------------------------------------------------------------------
- * OvsDeferredActionsQueueAlloc --
- *     The function allocates per-cpu deferred actions queue.
+ * '_OVS_DEFERRED_ACTION_QUEUE' structure is responsible for keeping track of
+ * all deferred actions. The maximum number of deferred actions should not
+ * exceed 'DEFERRED_ACTION_QUEUE_SIZE'.
  * --------------------------------------------------------------------------
  */
-BOOLEAN
-OvsDeferredActionsQueueAlloc()
-{
-    ovsDeferredActionQueue =
-        OvsAllocateMemoryPerCpu(sizeof(*ovsDeferredActionQueue),
-                                OVS_RECIRC_POOL_TAG);
-    if (!ovsDeferredActionQueue) {
-        return FALSE;
-    }
-    return TRUE;
-}
+typedef struct _OVS_DEFERRED_ACTION_QUEUE {
+    UINT32  head;
+    UINT32  tail;
+    OVS_DEFERRED_ACTION deferredActions[DEFERRED_ACTION_QUEUE_SIZE];
+} OVS_DEFERRED_ACTION_QUEUE, *POVS_DEFERRED_ACTION_QUEUE;
 
-/*
- * --------------------------------------------------------------------------
- * OvsDeferredActionsQueueFree --
- *     The function frees per-cpu deferred actions queue.
- * --------------------------------------------------------------------------
- */
-VOID
-OvsDeferredActionsQueueFree()
-{
-    OvsFreeMemoryWithTag(ovsDeferredActionQueue,
-                         OVS_RECIRC_POOL_TAG);
-    ovsDeferredActionQueue = NULL;
-}
+typedef struct _OVS_DEFERRED_ACTION_DATA {
+    OVS_DEFERRED_ACTION_QUEUE   queue;
+    UINT32                      level;
+} OVS_DEFERRED_ACTION_DATA, *POVS_DEFERRED_ACTION_DATA;
+
+static POVS_DEFERRED_ACTION_DATA deferredData = NULL;
 
 /*
  * --------------------------------------------------------------------------
- * OvsDeferredActionsLevelAlloc --
- *     The function allocates per-cpu deferred actions execution level.
+ * OvsDeferredActionsInit --
+ *     The function allocates all necessary deferred actions resources.
  * --------------------------------------------------------------------------
  */
-BOOLEAN
-OvsDeferredActionsLevelAlloc()
+NTSTATUS
+OvsDeferredActionsInit()
 {
-    ovsDeferredActionLevel =
-        OvsAllocateMemoryPerCpu(sizeof(*ovsDeferredActionLevel),
-                                OVS_RECIRC_POOL_TAG);
-    if (!ovsDeferredActionLevel) {
-        return FALSE;
+    NTSTATUS status = STATUS_SUCCESS;
+    ULONG count = KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS);
+
+    deferredData = OvsAllocateMemoryPerCpu(sizeof(*deferredData),
+                                           count,
+                                           OVS_RECIRC_POOL_TAG);
+    if (!deferredData) {
+        status = NDIS_STATUS_RESOURCES;
     }
-    return TRUE;
+
+    return status;
 }
 
 /*
  * --------------------------------------------------------------------------
- * OvsDeferredActionsLevelFree --
- *     The function frees per-cpu deferred actions execution level.
+ * OvsDeferredActionsCleanup --
+ *     The function frees all deferred actions resources.
  * --------------------------------------------------------------------------
  */
 VOID
-OvsDeferredActionsLevelFree()
+OvsDeferredActionsCleanup()
 {
-    OvsFreeMemoryWithTag(ovsDeferredActionLevel,
-                         OVS_RECIRC_POOL_TAG);
-    ovsDeferredActionLevel = NULL;
+    if (deferredData) {
+        OvsFreeMemoryWithTag(deferredData, OVS_RECIRC_POOL_TAG);
+        deferredData = NULL;
+    }
 }
 
 /*
@@ -104,7 +94,7 @@ OvsDeferredActionsQueueGet()
     }
 
     index = KeGetCurrentProcessorNumberEx(NULL);
-    queue = &ovsDeferredActionQueue[index];
+    queue = &deferredData[index].queue;
 
     if (oldIrql < DISPATCH_LEVEL) {
         KeLowerIrql(oldIrql);
@@ -123,7 +113,7 @@ OvsDeferredActionsQueueGet()
 UINT32
 OvsDeferredActionsLevelGet()
 {
-    UINT32 *level = NULL;
+    UINT32 level = 0;
     ULONG index = 0;
     KIRQL oldIrql = KeGetCurrentIrql();
 
@@ -132,13 +122,13 @@ OvsDeferredActionsLevelGet()
     }
 
     index = KeGetCurrentProcessorNumberEx(NULL);
-    level = &ovsDeferredActionLevel[index];
+    level = deferredData[index].level;
 
     if (oldIrql < DISPATCH_LEVEL) {
         KeLowerIrql(oldIrql);
     }
 
-    return *level;
+    return level;
 }
 
 /*
@@ -151,7 +141,6 @@ OvsDeferredActionsLevelGet()
 VOID
 OvsDeferredActionsLevelInc()
 {
-    UINT32 *level = NULL;
     ULONG index = 0;
     KIRQL oldIrql = KeGetCurrentIrql();
 
@@ -160,8 +149,7 @@ OvsDeferredActionsLevelInc()
     }
 
     index = KeGetCurrentProcessorNumberEx(NULL);
-    level = &ovsDeferredActionLevel[index];
-    (*level)++;
+    deferredData[index].level++;
 
     if (oldIrql < DISPATCH_LEVEL) {
         KeLowerIrql(oldIrql);
@@ -178,7 +166,6 @@ OvsDeferredActionsLevelInc()
 VOID
 OvsDeferredActionsLevelDec()
 {
-    UINT32 *level = NULL;
     ULONG index = 0;
     KIRQL oldIrql = KeGetCurrentIrql();
 
@@ -187,8 +174,7 @@ OvsDeferredActionsLevelDec()
     }
 
     index = KeGetCurrentProcessorNumberEx(NULL);
-    level = &ovsDeferredActionLevel[index];
-    (*level)--;
+    deferredData[index].level--;
 
     if (oldIrql < DISPATCH_LEVEL) {
         KeLowerIrql(oldIrql);
@@ -243,7 +229,7 @@ OvsDeferredActionsQueuePop(POVS_DEFERRED_ACTION_QUEUE queue)
         /* Reset the queue for the next packet. */
         OvsDeferredActionsQueueInit(queue);
     } else {
-        deferredAction = &queue->queue[queue->tail++];
+        deferredAction = &queue->deferredActions[queue->tail++];
     }
 
     if (oldIrql < DISPATCH_LEVEL) {
@@ -271,7 +257,7 @@ OvsDeferredActionsQueuePush(POVS_DEFERRED_ACTION_QUEUE queue)
     }
 
     if (queue->head < DEFERRED_ACTION_QUEUE_SIZE) {
-        deferredAction = &queue->queue[queue->head++];
+        deferredAction = &queue->deferredActions[queue->head++];
     }
 
     if (oldIrql < DISPATCH_LEVEL) {
diff --git a/datapath-windows/ovsext/Recirc.h b/datapath-windows/ovsext/Recirc.h
index ee05763..2b314ce 100644
--- a/datapath-windows/ovsext/Recirc.h
+++ b/datapath-windows/ovsext/Recirc.h
@@ -30,19 +30,6 @@ typedef struct _OVS_DEFERRED_ACTION {
 
 /*
  * --------------------------------------------------------------------------
- * '_OVS_DEFERRED_ACTION_QUEUE' structure is responsible for keeping track of
- * all deferred actions. The maximum number of deferred actions should not
- * exceed 'DEFERRED_ACTION_QUEUE_SIZE'.
- * --------------------------------------------------------------------------
- */
-typedef struct _OVS_DEFERRED_ACTION_QUEUE {
-    UINT32  head;
-    UINT32  tail;
-    OVS_DEFERRED_ACTION queue[DEFERRED_ACTION_QUEUE_SIZE];
-} OVS_DEFERRED_ACTION_QUEUE, *POVS_DEFERRED_ACTION_QUEUE;
-
-/*
- * --------------------------------------------------------------------------
  * OvsProcessDeferredActions --
  *     This function processes all deferred actions contained in the queue
  *     corresponding to the current CPU.
@@ -69,39 +56,21 @@ OvsAddDeferredActions(PNET_BUFFER_LIST packet,
 
 /*
  * --------------------------------------------------------------------------
- * OvsDeferredActionsQueueAlloc --
- *     The function allocates per-cpu deferred actions queue.
- * --------------------------------------------------------------------------
- */
-BOOLEAN
-OvsDeferredActionsQueueAlloc();
-
-/*
- * --------------------------------------------------------------------------
- * OvsDeferredActionsQueueFree --
- *     The function frees per-cpu deferred actions queue.
- * --------------------------------------------------------------------------
- */
-VOID
-OvsDeferredActionsQueueFree();
-
-/*
- * --------------------------------------------------------------------------
- * OvsDeferredActionsLevelAlloc --
- *     The function allocates per-cpu deferred actions execution level.
+ * OvsDeferredActionsInit --
+ *     The function allocates all necessary deferred actions resources.
  * --------------------------------------------------------------------------
  */
-BOOLEAN
-OvsDeferredActionsLevelAlloc();
+NTSTATUS
+OvsDeferredActionsInit();
 
 /*
  * --------------------------------------------------------------------------
- * OvsDeferredActionsLevelFree --
- *     The function frees per-cpu deferred actions execution level.
+ * OvsDeferredActionsCleanup --
+ *     The function frees all deferred actions resources.
  * --------------------------------------------------------------------------
  */
 VOID
-OvsDeferredActionsLevelFree();
+OvsDeferredActionsCleanup();
 
 /*
  * --------------------------------------------------------------------------
diff --git a/datapath-windows/ovsext/Util.c b/datapath-windows/ovsext/Util.c
index 14c4493..a1ce0e6 100644
--- a/datapath-windows/ovsext/Util.c
+++ b/datapath-windows/ovsext/Util.c
@@ -15,6 +15,7 @@
  */
 
 #include "precomp.h"
+#include "Recirc.h"
 #ifdef OVS_DBG_MOD
 #undef OVS_DBG_MOD
 #endif
@@ -118,13 +119,18 @@ OvsCompareString(PVOID string1, PVOID string2)
 }
 
 VOID *
-OvsAllocateMemoryPerCpu(size_t size, ULONG tag)
+OvsAllocateMemoryPerCpu(size_t size,
+                        size_t count,
+                        ULONG tag)
 {
     VOID *ptr = NULL;
-    ULONG count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
 
     ASSERT(KeQueryActiveGroupCount() == 1);
 
+    if (!count) {
+        count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
+    }
+
     ptr = OvsAllocateMemoryWithTag(count * size, tag);
     if (ptr) {
         RtlZeroMemory(ptr, count * size);
@@ -132,3 +138,27 @@ OvsAllocateMemoryPerCpu(size_t size, ULONG tag)
 
     return ptr;
 }
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsPerCpuDataInit --
+ *     The function allocates necessary per-processor resources.
+ * --------------------------------------------------------------------------
+ */
+NTSTATUS
+OvsPerCpuDataInit()
+{
+    return OvsDeferredActionsInit();
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsPerCpuDataCleanup --
+ *     The function frees all per-processor resources.
+ * --------------------------------------------------------------------------
+ */
+VOID
+OvsPerCpuDataCleanup()
+{
+    OvsDeferredActionsCleanup();
+}
diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h
index 038754d..78b926d 100644
--- a/datapath-windows/ovsext/Util.h
+++ b/datapath-windows/ovsext/Util.h
@@ -41,7 +41,7 @@
 VOID *OvsAllocateMemory(size_t size);
 VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag);
 VOID *OvsAllocateAlignedMemory(size_t size, UINT16 align);
-VOID *OvsAllocateMemoryPerCpu(size_t size, ULONG tag);
+VOID *OvsAllocateMemoryPerCpu(size_t size, size_t count, ULONG tag);
 VOID OvsFreeMemory(VOID *ptr);
 VOID OvsFreeMemoryWithTag(VOID *ptr, ULONG tag);
 VOID OvsFreeAlignedMemory(VOID *ptr);
@@ -94,4 +94,22 @@ VOID OvsAppendList(PLIST_ENTRY dst, PLIST_ENTRY src);
 
 BOOLEAN OvsCompareString(PVOID string1, PVOID string2);
 
+/*
+ * --------------------------------------------------------------------------
+ * OvsPerCpuDataInit --
+ *     The function allocates necessary per-processor resources.
+ * --------------------------------------------------------------------------
+ */
+NTSTATUS
+OvsPerCpuDataInit();
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsPerCpuDataCleanup --
+ *     The function frees all per-processor resources.
+ * --------------------------------------------------------------------------
+ */
+VOID
+OvsPerCpuDataCleanup();
+
 #endif /* __UTIL_H_ */
-- 
1.9.0.msysgit.0



More information about the dev mailing list