[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


 


Rackspace

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