[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH] Add DPC watchdog avoidance to receiver and transmitter poll
Under HCK MPE testing it's possible for both receiver and transmitter polling loops to run long enough to hit the DPC watchdog. This patch avoids the problem by terminating the polling loops after a 'batch' (currently 1/4 of the ring) and then checking the remaining time before the watchdog fires. If the remaining time is still more than half the total time then another poll is done, otherwise a timer is scheduled to complete the work. Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> --- src/xenvif/receiver.c | 103 ++++++++++++++++++++++++++++++------------ src/xenvif/transmitter.c | 115 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 158 insertions(+), 60 deletions(-) diff --git a/src/xenvif/receiver.c b/src/xenvif/receiver.c index 29877f2..538971e 100644 --- a/src/xenvif/receiver.c +++ b/src/xenvif/receiver.c @@ -86,6 +86,8 @@ typedef struct _XENVIF_RECEIVER_RING { PXENBUS_EVTCHN_CHANNEL Channel; KDPC Dpc; ULONG Dpcs; + KTIMER Timer; + KDPC TimerDpc; ULONG Events; PXENVIF_RECEIVER_FRAGMENT Pending[XENVIF_RECEIVER_MAXIMUM_FRAGMENT_ID + 1]; ULONG RequestsPosted; @@ -1783,7 +1785,7 @@ ReceiverRingDebugCallback( Ring->Dpcs); } -static DECLSPEC_NOINLINE VOID +static DECLSPEC_NOINLINE BOOLEAN ReceiverRingPoll( IN PXENVIF_RECEIVER_RING Ring ) @@ -1792,12 +1794,14 @@ ReceiverRingPoll( PXENVIF_RECEIVER Receiver; PXENVIF_FRONTEND Frontend; - - if (!(Ring->Enabled)) - return; + BOOLEAN Retry; Receiver = Ring->Receiver; Frontend = Receiver->Frontend; + Retry = FALSE; + + if (!Ring->Enabled) + goto done; for (;;) { BOOLEAN Error; @@ -1827,15 +1831,14 @@ ReceiverRingPoll( KeMemoryBarrier(); - if (rsp_cons == rsp_prod) + if (rsp_cons == rsp_prod || Retry) break; - while (rsp_cons != rsp_prod) { + while (rsp_cons != rsp_prod && !Retry) { netif_rx_response_t *rsp; uint16_t id; PXENVIF_RECEIVER_FRAGMENT Fragment; PMDL Mdl; - RING_IDX req_prod; rsp = RING_GET_RESPONSE(&Ring->Front, rsp_cons); @@ -1942,6 +1945,9 @@ ReceiverRingPoll( InsertTailList(&Ring->PacketList, &Packet->ListEntry); } + if (rsp_cons - Ring->Front.rsp_cons > XENVIF_RECEIVER_BATCH(Ring)) + Retry = TRUE; + Error = FALSE; Info = 0; MaximumSegmentSize = 0; @@ -1949,16 +1955,6 @@ ReceiverRingPoll( flags = 0; TailMdl = NULL; } - - KeMemoryBarrier(); - - req_prod = Ring->Front.req_prod_pvt; - - if (req_prod - rsp_cons < XENVIF_RECEIVER_BATCH(Ring) && - !__ReceiverRingIsStopped(Ring)) { - Ring->Front.rsp_cons = rsp_cons; - ReceiverRingFill(Ring); - } } ASSERT(!Error); ASSERT(!Extra); @@ -1978,6 +1974,9 @@ ReceiverRingPoll( if (!__ReceiverRingIsStopped(Ring)) ReceiverRingFill(Ring); +done: + return Retry; + #undef XENVIF_RECEIVER_BATCH } @@ -1999,6 +1998,37 @@ __ReceiverRingUnmask( FALSE); } +static FORCEINLINE BOOLEAN +__ReceiverRingDpcTimeout( + IN PXENVIF_RECEIVER_RING Ring + ) +{ + KDPC_WATCHDOG_INFORMATION Watchdog; + NTSTATUS status; + + UNREFERENCED_PARAMETER(Ring); + + RtlZeroMemory(&Watchdog, sizeof (Watchdog)); + + status = KeQueryDpcWatchdogInformation(&Watchdog); + ASSERT(NT_SUCCESS(status)); + + if (Watchdog.DpcTimeLimit == 0 || + Watchdog.DpcWatchdogLimit == 0) + return FALSE; + + if (Watchdog.DpcTimeCount > (Watchdog.DpcTimeLimit / 2) && + Watchdog.DpcWatchdogCount > (Watchdog.DpcWatchdogLimit / 2)) + return FALSE; + + return TRUE; +} + +#define TIME_US(_us) ((_us) * 10) +#define TIME_MS(_ms) (TIME_US((_ms) * 1000)) +#define TIME_S(_s) (TIME_MS((_s) * 1000)) +#define TIME_RELATIVE(_t) (-(_t)) + __drv_functionClass(KDEFERRED_ROUTINE) __drv_maxIRQL(DISPATCH_LEVEL) __drv_minIRQL(DISPATCH_LEVEL) @@ -2020,15 +2050,27 @@ ReceiverRingDpc( ASSERT(Ring != NULL); - Ring->Dpcs++; + for (;;) { + BOOLEAN Retry; - __ReceiverRingAcquireLock(Ring); + __ReceiverRingAcquireLock(Ring); + Retry = ReceiverRingPoll(Ring); + __ReceiverRingReleaseLock(Ring); + + if (!Retry) { + __ReceiverRingUnmask(Ring); + break; + } - if (Ring->Enabled) - ReceiverRingPoll(Ring); + if (__ReceiverRingDpcTimeout(Ring)) { + LARGE_INTEGER Delay; - __ReceiverRingReleaseLock(Ring); - __ReceiverRingUnmask(Ring); + Delay.QuadPart = TIME_RELATIVE(TIME_US(100)); + + KeSetTimer(&Ring->Timer, Delay, &Ring->TimerDpc); + break; + } + } } KSERVICE_ROUTINE ReceiverRingEvtchnCallback; @@ -2049,7 +2091,8 @@ ReceiverRingEvtchnCallback( Ring->Events++; - (VOID) KeInsertQueueDpc(&Ring->Dpc, NULL, NULL); + if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL)) + Ring->Dpcs++; Receiver = Ring->Receiver; Frontend = Receiver->Frontend; @@ -2061,11 +2104,6 @@ ReceiverRingEvtchnCallback( return TRUE; } -#define TIME_US(_us) ((_us) * 10) -#define TIME_MS(_ms) (TIME_US((_ms) * 1000)) -#define TIME_S(_s) (TIME_MS((_s) * 1000)) -#define TIME_RELATIVE(_t) (-(_t)) - #define XENVIF_RECEIVER_WATCHDOG_PERIOD 30 static NTSTATUS @@ -2168,6 +2206,8 @@ __ReceiverRingInitialize( InitializeListHead(&(*Ring)->PacketList); KeInitializeDpc(&(*Ring)->Dpc, ReceiverRingDpc, *Ring); + KeInitializeTimer(&(*Ring)->Timer); + KeInitializeDpc(&(*Ring)->TimerDpc, ReceiverRingDpc, *Ring); status = ThreadCreate(ReceiverRingWatchdog, *Ring, @@ -2180,6 +2220,8 @@ __ReceiverRingInitialize( fail3: Error("fail3\n"); + RtlZeroMemory(&(*Ring)->TimerDpc, sizeof (KDPC)); + RtlZeroMemory(&(*Ring)->Timer, sizeof (KTIMER)); RtlZeroMemory(&(*Ring)->Dpc, sizeof (KDPC)); RtlZeroMemory(&(*Ring)->PacketList, sizeof (LIST_ENTRY)); @@ -2344,6 +2386,7 @@ __ReceiverRingConnect( ASSERT(NT_SUCCESS(status)); KeSetTargetProcessorDpcEx(&Ring->Dpc, &ProcNumber); + KeSetTargetProcessorDpcEx(&Ring->TimerDpc, &ProcNumber); (VOID) XENBUS_EVTCHN(Bind, &Receiver->EvtchnInterface, @@ -2629,6 +2672,8 @@ __ReceiverRingTeardown( Receiver = Ring->Receiver; Frontend = Receiver->Frontend; + RtlZeroMemory(&Ring->TimerDpc, sizeof (KDPC)); + RtlZeroMemory(&Ring->Timer, sizeof (KTIMER)); RtlZeroMemory(&Ring->Dpc, sizeof (KDPC)); Ring->BackfillSize = 0; diff --git a/src/xenvif/transmitter.c b/src/xenvif/transmitter.c index fdb1334..3aa6366 100644 --- a/src/xenvif/transmitter.c +++ b/src/xenvif/transmitter.c @@ -180,6 +180,8 @@ typedef struct _XENVIF_TRANSMITTER_RING { PXENBUS_EVTCHN_CHANNEL Channel; KDPC Dpc; ULONG Dpcs; + KTIMER Timer; + KDPC TimerDpc; ULONG Events; BOOLEAN Connected; BOOLEAN Enabled; @@ -2351,7 +2353,7 @@ __TransmitterRingCompletePacket( Ring->PacketsCompleted++; } -static DECLSPEC_NOINLINE VOID +static DECLSPEC_NOINLINE BOOLEAN TransmitterRingPoll( IN PXENVIF_TRANSMITTER_RING Ring ) @@ -2360,14 +2362,18 @@ TransmitterRingPoll( PXENVIF_TRANSMITTER Transmitter; PXENVIF_FRONTEND Frontend; + BOOLEAN Retry; Transmitter = Ring->Transmitter; Frontend = Transmitter->Frontend; + Retry = FALSE; + + if (!Ring->Enabled) + goto done; for (;;) { RING_IDX rsp_prod; RING_IDX rsp_cons; - ULONG Delta; KeMemoryBarrier(); @@ -2376,10 +2382,10 @@ TransmitterRingPoll( KeMemoryBarrier(); - if (rsp_cons == rsp_prod) + if (rsp_cons == rsp_prod || Retry) break; - while (rsp_cons != rsp_prod) { + while (rsp_cons != rsp_prod && !Retry) { netif_tx_response_t *rsp; uint16_t id; PXENVIF_TRANSMITTER_FRAGMENT Fragment; @@ -2471,10 +2477,8 @@ TransmitterRingPoll( Fragment->Extra = FALSE; __TransmitterPutFragment(Ring, Fragment); - if (Packet == NULL) { - RtlZeroMemory(rsp, sizeof (netif_tx_response_t)); + if (Packet == NULL) continue; - } --Packet->Reference; @@ -2495,8 +2499,6 @@ TransmitterRingPoll( } } - RtlZeroMemory(rsp, sizeof (netif_tx_response_t)); - if (Packet->Reference != 0) continue; @@ -2504,19 +2506,20 @@ TransmitterRingPoll( Packet->Completion.Status = XENVIF_TRANSMITTER_PACKET_OK; __TransmitterRingCompletePacket(Ring, Packet); + + if (rsp_cons - Ring->Front.rsp_cons > XENVIF_TRANSMITTER_BATCH(Ring)) + Retry = TRUE; } KeMemoryBarrier(); Ring->Front.rsp_cons = rsp_cons; - - Delta = Ring->Front.req_prod_pvt - rsp_cons; - Delta = __min(Delta, XENVIF_TRANSMITTER_BATCH(Ring)); - Delta = __max(Delta, 1); - - Ring->Shared->rsp_event = rsp_cons + Delta; + Ring->Shared->rsp_event = rsp_cons + 1; } +done: + return Retry; + #undef XENVIF_TRANSMITTER_BATCH } @@ -2930,6 +2933,37 @@ __TransmitterRingUnmask( FALSE); } +static FORCEINLINE BOOLEAN +__TransmitterRingDpcTimeout( + IN PXENVIF_TRANSMITTER_RING Ring + ) +{ + KDPC_WATCHDOG_INFORMATION Watchdog; + NTSTATUS status; + + UNREFERENCED_PARAMETER(Ring); + + RtlZeroMemory(&Watchdog, sizeof (Watchdog)); + + status = KeQueryDpcWatchdogInformation(&Watchdog); + ASSERT(NT_SUCCESS(status)); + + if (Watchdog.DpcTimeLimit == 0 || + Watchdog.DpcWatchdogLimit == 0) + return FALSE; + + if (Watchdog.DpcTimeCount > (Watchdog.DpcTimeLimit / 2) && + Watchdog.DpcWatchdogCount > (Watchdog.DpcWatchdogLimit / 2)) + return FALSE; + + return TRUE; +} + +#define TIME_US(_us) ((_us) * 10) +#define TIME_MS(_ms) (TIME_US((_ms) * 1000)) +#define TIME_S(_s) (TIME_MS((_s) * 1000)) +#define TIME_RELATIVE(_t) (-(_t)) + __drv_functionClass(KDEFERRED_ROUTINE) __drv_maxIRQL(DISPATCH_LEVEL) __drv_minIRQL(DISPATCH_LEVEL) @@ -2951,15 +2985,27 @@ TransmitterRingDpc( ASSERT(Ring != NULL); - Ring->Dpcs++; + for (;;) { + BOOLEAN Retry; - __TransmitterRingAcquireLock(Ring); + __TransmitterRingAcquireLock(Ring); + Retry = TransmitterRingPoll(Ring); + __TransmitterRingReleaseLock(Ring); - if (Ring->Enabled) - TransmitterRingPoll(Ring); + if (!Retry) { + __TransmitterRingUnmask(Ring); + break; + } - __TransmitterRingReleaseLock(Ring); - __TransmitterRingUnmask(Ring); + if (__TransmitterRingDpcTimeout(Ring)) { + LARGE_INTEGER Delay; + + Delay.QuadPart = TIME_RELATIVE(TIME_US(100)); + + KeSetTimer(&Ring->Timer, Delay, &Ring->TimerDpc); + break; + } + } } KSERVICE_ROUTINE TransmitterRingEvtchnCallback; @@ -2985,16 +3031,12 @@ TransmitterRingEvtchnCallback( Ring->Events++; - (VOID) KeInsertQueueDpc(&Ring->Dpc, NULL, NULL); + if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL)) + Ring->Dpcs++; return TRUE; } -#define TIME_US(_us) ((_us) * 10) -#define TIME_MS(_ms) (TIME_US((_ms) * 1000)) -#define TIME_S(_s) (TIME_MS((_s) * 1000)) -#define TIME_RELATIVE(_t) (-(_t)) - #define XENVIF_TRANSMITTER_WATCHDOG_PERIOD 30 static NTSTATUS @@ -3044,7 +3086,7 @@ TransmitterRingWatchdog( // Try to move things along __TransmitterRingSend(Ring); - TransmitterRingPoll(Ring); + (VOID) TransmitterRingPoll(Ring); } PacketsQueued = Ring->PacketsQueued; @@ -3089,6 +3131,8 @@ __TransmitterRingInitialize( InitializeListHead(&(*Ring)->PacketComplete); KeInitializeDpc(&(*Ring)->Dpc, TransmitterRingDpc, *Ring); + KeInitializeTimer(&(*Ring)->Timer); + KeInitializeDpc(&(*Ring)->TimerDpc, TransmitterRingDpc, *Ring); status = ThreadCreate(TransmitterRingWatchdog, *Ring, @@ -3101,6 +3145,8 @@ __TransmitterRingInitialize( fail3: Error("fail3\n"); + RtlZeroMemory(&(*Ring)->TimerDpc, sizeof (KDPC)); + RtlZeroMemory(&(*Ring)->Timer, sizeof (KTIMER)); RtlZeroMemory(&(*Ring)->Dpc, sizeof (KDPC)); RtlZeroMemory(&(*Ring)->PacketComplete, sizeof (LIST_ENTRY)); @@ -3344,6 +3390,7 @@ __TransmitterRingConnect( ASSERT(NT_SUCCESS(status)); KeSetTargetProcessorDpcEx(&Ring->Dpc, &ProcNumber); + KeSetTargetProcessorDpcEx(&Ring->TimerDpc, &ProcNumber); (VOID) XENBUS_EVTCHN(Bind, &Transmitter->EvtchnInterface, @@ -3587,7 +3634,6 @@ __TransmitterRingDisable( __TransmitterRingAcquireLock(Ring); ASSERT(Ring->Enabled); - Ring->Enabled = FALSE; // Release any fragments associated with a pending packet Packet = __TransmitterRingUnprepareFragments(Ring); @@ -3636,7 +3682,7 @@ __TransmitterRingDisable( // Try to move things along __TransmitterRingSend(Ring); - TransmitterRingPoll(Ring); + (VOID) TransmitterRingPoll(Ring); if (State != XenbusStateConnected) __TransmitterRingFakeResponses(Ring); @@ -3649,6 +3695,8 @@ __TransmitterRingDisable( KeStallExecutionProcessor(1000); // 1ms } + Ring->Enabled = FALSE; + __TransmitterRingReleaseLock(Ring); } @@ -3751,6 +3799,10 @@ __TransmitterRingTeardown( Transmitter = Ring->Transmitter; Frontend = Transmitter->Frontend; + Ring->Dpcs = 0; + + RtlZeroMemory(&Ring->TimerDpc, sizeof (KDPC)); + RtlZeroMemory(&Ring->Timer, sizeof (KTIMER)); RtlZeroMemory(&Ring->Dpc, sizeof (KDPC)); ASSERT3U(Ring->PacketsCompleted, ==, Ring->PacketsSent); @@ -4787,7 +4839,8 @@ TransmitterNotify( Ring = Transmitter->Ring[Index]; - (VOID) KeInsertQueueDpc(&Ring->Dpc, NULL, NULL); + if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL)) + Ring->Dpcs++; } VOID -- 2.1.1 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |