]> xenbits.xensource.com Git - pvdrivers/win/xenvbd.git/commitdiff
Add DPC timeout check
authorOwen Smith <owen.smith@citrix.com>
Mon, 21 Aug 2017 14:37:00 +0000 (15:37 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Mon, 21 Aug 2017 14:39:39 +0000 (15:39 +0100)
Check the DPC has not exceeded 1/2 its alloted time every
* 1/4 ring of responses processed
* all outstanding prepared requests submitted
* 1 queued SRB prepared

Signed-off-by: Owen Smith <owen.smith@citrix.com>
src/xenvbd/blockring.c
src/xenvbd/blockring.h
src/xenvbd/frontend.c
src/xenvbd/frontend.h
src/xenvbd/notifier.c
src/xenvbd/target.c
src/xenvbd/target.h

index e00b64ae7f0c37b23ea62bf262c1d27e9e8fdb25..cf15a6f7a0faf42acb64f566219848d4460a4e88 100644 (file)
@@ -506,12 +506,13 @@ BlockRingDebugCallback(
     BlockRing->Submitted = BlockRing->Received = 0;
 }
 
-VOID
+BOOLEAN
 BlockRingPoll(
     IN  PXENVBD_BLOCKRING           BlockRing
     )
 {
     PXENVBD_TARGET Target = FrontendGetTarget(BlockRing->Frontend);
+    BOOLEAN        Retry = FALSE;
 
     ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
     KeAcquireSpinLockAtDpcLevel(&BlockRing->Lock);
@@ -532,10 +533,10 @@ BlockRingPoll(
 
         KeMemoryBarrier();
 
-        if (rsp_cons == rsp_prod)
+        if (rsp_cons == rsp_prod || Retry)
             break;
 
-        while (rsp_cons != rsp_prod) {
+        while (rsp_cons != rsp_prod && !Retry) {
             blkif_response_t*   Response;
             ULONG               Tag;
 
@@ -548,6 +549,9 @@ BlockRingPoll(
             }
 
             RtlZeroMemory(Response, sizeof(union blkif_sring_entry));
+
+            if (rsp_cons - BlockRing->FrontRing.rsp_cons > RING_SIZE(&BlockRing->FrontRing) / 4)
+                Retry = TRUE;
         }
 
         KeMemoryBarrier();
@@ -558,6 +562,8 @@ BlockRingPoll(
 
 done:
     KeReleaseSpinLockFromDpcLevel(&BlockRing->Lock);
+
+    return Retry;
 }
 
 BOOLEAN
index 1117d739de50fb565518977e9b7edc4a647d8e3a..98fe278286ec540188d59563fe7e7fe0976086d3 100644 (file)
@@ -83,7 +83,7 @@ BlockRingDebugCallback(
     IN  PXENBUS_DEBUG_INTERFACE     Debug
     );
 
-extern VOID
+extern BOOLEAN
 BlockRingPoll(
     IN  PXENVBD_BLOCKRING           BlockRing
     );
index c909ea819f3ffa626929fd118dbb5ad73940a41a..1e2b0260655fba2ea0065144528a7f0ad4743334 100644 (file)
@@ -326,13 +326,17 @@ out:
 
 //=============================================================================
 __drv_requiresIRQL(DISPATCH_LEVEL)
-VOID
+BOOLEAN
 FrontendNotifyResponses(
     __in  PXENVBD_FRONTEND        Frontend
     )
 {
-    BlockRingPoll(Frontend->BlockRing);
-    TargetSubmitRequests(Frontend->Target);
+    BOOLEAN     Retry = FALSE;
+
+    Retry |= BlockRingPoll(Frontend->BlockRing);
+    Retry |= TargetSubmitRequests(Frontend->Target);
+
+    return Retry;
 }
 
 //=============================================================================
index 8a6cc0453896802da018c3fa04c8ffec238ce2e2..4490aeb236e63e61eab143080c6bb0447cd6fe61 100644 (file)
@@ -149,7 +149,7 @@ FrontendWriteUsage(
 
 // Ring
 __drv_requiresIRQL(DISPATCH_LEVEL)
-extern VOID
+extern BOOLEAN
 FrontendNotifyResponses(
     __in  PXENVBD_FRONTEND        Frontend
     );
index a87c3bd54d5fee385d28cd33b862d629b426e8b2..22bfe001a832526fdad444db6d548fa695f8fcfb 100644 (file)
@@ -50,6 +50,8 @@ struct _XENVBD_NOTIFIER {
     ULONG                           NumInts;
     ULONG                           NumDpcs;
     KDPC                            Dpc;
+    KDPC                            TimerDpc;
+    KTIMER                          Timer;
 };
 
 #define NOTIFIER_POOL_TAG           'yfNX'
@@ -95,6 +97,37 @@ NotifierInterrupt(
     return TRUE;
 }
 
+static FORCEINLINE BOOLEAN
+__NotifierDpcTimeout(
+    IN  PXENVBD_NOTIFIER        Notifier
+    )
+{
+    KDPC_WATCHDOG_INFORMATION   Watchdog;
+    NTSTATUS                    status;
+
+    UNREFERENCED_PARAMETER(Notifier);
+
+    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))
+
 KDEFERRED_ROUTINE NotifierDpc;
 
 VOID 
@@ -116,12 +149,25 @@ NotifierDpc(
     if (!Notifier->Connected)
         return;
 
-    FrontendNotifyResponses(Notifier->Frontend);
+    for (;;) {
+        if (!FrontendNotifyResponses(Notifier->Frontend)) {
+            XENBUS_EVTCHN(Unmask,
+                          &Notifier->EvtchnInterface,
+                          Notifier->Channel,
+                          FALSE);
+            break;
+        }
+        if (__NotifierDpcTimeout(Notifier)) {
+            LARGE_INTEGER   Delay;
 
-    XENBUS_EVTCHN(Unmask,
-                  &Notifier->EvtchnInterface,
-                  Notifier->Channel,
-                  FALSE);
+            Delay.QuadPart = TIME_RELATIVE(TIME_US(100));
+
+            KeSetTimer(&Notifier->Timer,
+                       Delay,
+                       &Notifier->TimerDpc);
+            break;
+        }
+    }
 }
 
 NTSTATUS
@@ -136,6 +182,8 @@ NotifierCreate(
 
     (*Notifier)->Frontend = Frontend;
     KeInitializeDpc(&(*Notifier)->Dpc, NotifierDpc, *Notifier);
+    KeInitializeDpc(&(*Notifier)->TimerDpc, NotifierDpc, *Notifier);
+    KeInitializeTimer(&(*Notifier)->Timer);
 
     return STATUS_SUCCESS;
 
@@ -150,6 +198,8 @@ NotifierDestroy(
 {
     Notifier->Frontend = NULL;
     RtlZeroMemory(&Notifier->Dpc, sizeof(KDPC));
+    RtlZeroMemory(&Notifier->TimerDpc, sizeof(KDPC));
+    RtlZeroMemory(&Notifier->Timer, sizeof(KTIMER));
 
     ASSERT(IsZeroMemory(Notifier, sizeof(XENVBD_NOTIFIER)));
     
@@ -252,6 +302,12 @@ NotifierDisable(
     ASSERT(Notifier->Enabled == TRUE);
 
     Notifier->Enabled = FALSE;
+
+    //
+    // No new timers can be scheduled once Enabled goes to FALSE.
+    // Cancel any existing ones.
+    //
+    (VOID) KeCancelTimer(&Notifier->Timer);
 }
 
 VOID
index ffffa3ef85dc7ed4549b19f0461c7b02229b430a..697f3098d430cbead64d9019124b5a9443fc62bb 100644 (file)
@@ -1254,11 +1254,13 @@ BlkifOperationName(
     }
 }
 
-VOID
+BOOLEAN
 TargetSubmitRequests(
     IN  PXENVBD_TARGET  Target
     )
 {
+    BOOLEAN             Retry = FALSE;
+
     for (;;) {
         // submit all prepared requests (0 or more requests)
         // return TRUE if submitted 0 or more requests from prepared queue
@@ -1271,10 +1273,17 @@ TargetSubmitRequests(
         // return FALSE if prepare failed or fresh queue empty
         if (!TargetPrepareFresh(Target))
             break;
+
+        // back off, check DPC timeout and try again
+        Retry = TRUE;
+        break;
     }
 
     // if no requests/SRBs outstanding, complete any shutdown SRBs
-    TargetCompleteShutdown(Target);
+    if (!Retry)
+        TargetCompleteShutdown(Target);
+
+    return Retry;
 }
 
 VOID
index 1e2b3ed369cef250fe6a309bc6f697f881f31a22..b790eb42a018cd5e25ef3372fded51766eefcf19 100644 (file)
@@ -93,7 +93,7 @@ TargetSetDeviceObject(
     IN  PDEVICE_OBJECT  DeviceObject
     );
 
-extern VOID
+extern BOOLEAN
 TargetSubmitRequests(
     IN  PXENVBD_TARGET  Target
     );