win-pvdrivers

view xenpci/xenpci_highsync.c @ 1106:2d392ecdd366

Fix race is xenvbd causing 30 second freeze under high load
author James Harper <james.harper@bendigoit.com.au>
date Tue Nov 11 23:08:11 2014 +1100 (2014-11-11)
parents 27bd2a5a4704
children
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
4 Copyright (c) 2014, James Harper
5 All rights reserved.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of James Harper nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL JAMES HARPER BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
30 #include "xenpci.h"
32 /* Not really necessary but keeps PREfast happy */
33 #if (VER_PRODUCTBUILD >= 7600)
34 static KDEFERRED_ROUTINE XenPci_HighSyncCallFunction0;
35 static KDEFERRED_ROUTINE XenPci_HighSyncCallFunctionN;
36 #endif
38 /*
39 we need these intrinsics as even going to HIGH_LEVEL doesn't ensure that interrupts are completely disabled
40 */
41 #pragma intrinsic(_disable)
42 #pragma intrinsic(_enable)
44 struct {
45 volatile ULONG do_spin;
46 volatile LONG nr_procs_at_dispatch_level;
47 volatile LONG nr_spinning_at_sync_level;
48 KDPC dpcs[MAX_VIRT_CPUS];
49 KEVENT highsync_complete_event;
50 KIRQL sync_level;
51 PXENPCI_HIGHSYNC_FUNCTION function0;
52 PXENPCI_HIGHSYNC_FUNCTION functionN;
53 PVOID context;
54 } typedef highsync_info_t;
56 static VOID
57 XenPci_HighSyncCallFunction0(PRKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2) {
58 highsync_info_t *highsync_info = Context;
59 ULONG ActiveProcessorCount;
60 KIRQL old_irql;
62 UNREFERENCED_PARAMETER(Dpc);
63 UNREFERENCED_PARAMETER(SystemArgument1);
64 UNREFERENCED_PARAMETER(SystemArgument2);
66 FUNCTION_ENTER();
67 #if (NTDDI_VERSION >= NTDDI_WINXP)
68 ActiveProcessorCount = (ULONG)KeNumberProcessors;
69 #else
70 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
71 #endif
72 InterlockedIncrement(&highsync_info->nr_procs_at_dispatch_level);
73 if (highsync_info->sync_level > DISPATCH_LEVEL) {
74 while (highsync_info->nr_procs_at_dispatch_level < (LONG)ActiveProcessorCount) {
75 KeStallExecutionProcessor(1);
76 KeMemoryBarrier();
77 }
78 }
79 _disable(); //__asm cli;
80 KeRaiseIrql(highsync_info->sync_level, &old_irql);
81 while (highsync_info->nr_spinning_at_sync_level < (LONG)ActiveProcessorCount - 1) {
82 KeStallExecutionProcessor(1);
83 KeMemoryBarrier();
84 }
85 highsync_info->function0(highsync_info->context);
86 KeLowerIrql(old_irql);
87 _enable(); //__asm sti;
88 highsync_info->do_spin = FALSE;
89 KeMemoryBarrier();
90 /* wait for all the other processors to complete spinning, just in case it matters */
91 while (highsync_info->nr_spinning_at_sync_level) {
92 KeStallExecutionProcessor(1);
93 KeMemoryBarrier();
94 }
95 InterlockedDecrement(&highsync_info->nr_procs_at_dispatch_level);
96 /* wait until nr_procs_at_dispatch_level drops to 0 indicating that nothing else requires highsync_info */
97 while (highsync_info->nr_procs_at_dispatch_level) {
98 KeStallExecutionProcessor(1);
99 KeMemoryBarrier();
100 }
101 KeSetEvent(&highsync_info->highsync_complete_event, IO_NO_INCREMENT, FALSE);
103 FUNCTION_EXIT();
104 }
106 static VOID
107 XenPci_HighSyncCallFunctionN(PRKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2) {
108 highsync_info_t *highsync_info = Context;
109 ULONG ActiveProcessorCount;
110 KIRQL old_irql;
112 UNREFERENCED_PARAMETER(Dpc);
113 UNREFERENCED_PARAMETER(SystemArgument1);
114 UNREFERENCED_PARAMETER(SystemArgument2);
116 FUNCTION_ENTER();
117 FUNCTION_MSG("(CPU = %d)\n", KeGetCurrentProcessorNumber());
119 FUNCTION_MSG("CPU %d spinning...\n", KeGetCurrentProcessorNumber());
120 InterlockedIncrement(&highsync_info->nr_procs_at_dispatch_level);
121 if (highsync_info->sync_level > DISPATCH_LEVEL) {
122 #if (NTDDI_VERSION >= NTDDI_WINXP)
123 ActiveProcessorCount = (ULONG)KeNumberProcessors;
124 #else
125 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
126 #endif
127 while (highsync_info->nr_procs_at_dispatch_level < (LONG)ActiveProcessorCount) {
128 KeStallExecutionProcessor(1);
129 KeMemoryBarrier();
130 }
131 }
132 _disable(); //__asm cli;
133 KeRaiseIrql(highsync_info->sync_level, &old_irql);
134 InterlockedIncrement(&highsync_info->nr_spinning_at_sync_level);
135 while(highsync_info->do_spin) {
136 KeStallExecutionProcessor(1);
137 KeMemoryBarrier();
138 }
139 highsync_info->functionN(highsync_info->context);
140 KeLowerIrql(old_irql);
141 _enable(); //__asm sti;
142 InterlockedDecrement(&highsync_info->nr_spinning_at_sync_level);
143 InterlockedDecrement(&highsync_info->nr_procs_at_dispatch_level);
144 FUNCTION_EXIT();
145 return;
146 }
148 VOID
149 XenPci_HighSync(PXENPCI_HIGHSYNC_FUNCTION function0, PXENPCI_HIGHSYNC_FUNCTION functionN, PVOID context) {
150 ULONG ActiveProcessorCount;
151 ULONG i;
152 highsync_info_t *highsync_info;
153 KIRQL old_irql;
155 UNREFERENCED_PARAMETER(context);
156 FUNCTION_ENTER();
158 highsync_info = ExAllocatePoolWithTag(NonPagedPool, sizeof(highsync_info_t), XENPCI_POOL_TAG);
159 RtlZeroMemory(highsync_info, sizeof(highsync_info_t));
160 KeInitializeEvent(&highsync_info->highsync_complete_event, SynchronizationEvent, FALSE);
161 highsync_info->function0 = function0;
162 highsync_info->functionN = functionN;
163 highsync_info->context = context;
164 highsync_info->sync_level = HIGH_LEVEL;
166 #if (NTDDI_VERSION >= NTDDI_WINXP)
167 ActiveProcessorCount = (ULONG)KeNumberProcessors;
168 #else
169 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
170 #endif
172 /* Go to HIGH_LEVEL to prevent any races with Dpc's on the current processor */
173 KeRaiseIrql(highsync_info->sync_level, &old_irql);
175 highsync_info->do_spin = TRUE;
176 for (i = 0; i < ActiveProcessorCount; i++) {
177 if (i == 0)
178 KeInitializeDpc(&highsync_info->dpcs[i], XenPci_HighSyncCallFunction0, highsync_info);
179 else
180 KeInitializeDpc(&highsync_info->dpcs[i], XenPci_HighSyncCallFunctionN, highsync_info);
181 KeSetTargetProcessorDpc(&highsync_info->dpcs[i], (CCHAR)i);
182 KeSetImportanceDpc(&highsync_info->dpcs[i], HighImportance);
183 FUNCTION_MSG("queuing Dpc for CPU %d\n", i);
184 KeInsertQueueDpc(&highsync_info->dpcs[i], NULL, NULL);
185 }
186 FUNCTION_MSG("All Dpc's queued\n");
188 KeMemoryBarrier();
189 KeLowerIrql(old_irql);
191 FUNCTION_MSG("Waiting for highsync_complete_event\n");
192 KeWaitForSingleObject(&highsync_info->highsync_complete_event, Executive, KernelMode, FALSE, NULL);
193 #if (NTDDI_VERSION >= NTDDI_WINXP)
194 KeFlushQueuedDpcs();
195 #else
196 {
197 /* just wait 1 second until all DPC's finish - not ideal but it's only for W2K */
198 LARGE_INTEGER interval;
199 interval.QuadPart = -1 * 1000 * 1000 * 10; /* 1 second */
200 KeDelayExecutionThread(KernelMode, FALSE, &interval);
201 }
202 #endif
203 ExFreePoolWithTag(highsync_info, XENPCI_POOL_TAG);
204 FUNCTION_EXIT();
205 }