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 <svintu...@cloudbasesolutions.com> Reported-by: Sorin Vinturis <svintu...@cloudbasesolutions.com> Reported-at: https://github.com/openvswitch/ovs-issues/issues/112 --- v2: Correctly reallocate per-cpu data structures when a new processor is about to be added to the system. v3: Per-cpu variables are allocated for the maximum number of processors supported by the system. --- datapath-windows/ovsext/Datapath.c | 13 +++-- datapath-windows/ovsext/Datapath.h | 2 +- datapath-windows/ovsext/Driver.c | 5 +- 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, 114 insertions(+), 105 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..2771015 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; 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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev