]> xenbits.xensource.com Git - people/pauldu/xenbus.git/commitdiff
watchdog watchdog
authorPaul Durrant <pdurrant@amazon.com>
Wed, 18 Nov 2020 15:57:44 +0000 (15:57 +0000)
committerPaul Durrant <pdurrant@amazon.com>
Wed, 18 Nov 2020 18:05:53 +0000 (18:05 +0000)
Signed-off-by: Paul Durrant <pdurrant@amazon.com>
include/xen.h
src/xen/sched.c
src/xen/system.c
src/xenbus/fdo.c

index 4698a33aa4881c7ec648b874cc1c7fc4a35ccc64..7371a2bf21f56c033dfd31a51fd72879a5db553b 100644 (file)
@@ -309,6 +309,13 @@ SchedYield(
     VOID
     );
 
+XEN_API
+NTSTATUS
+SchedWatchdog(
+    IN OUT  PULONG  Id,
+    IN      ULONG   Seconds
+    );
+
 // XEN VERSION
 
 __checkReturn
@@ -466,6 +473,18 @@ SystemRealTimeIsUniversal(
     VOID
     );
 
+XEN_API
+NTSTATUS
+SystemSetWatchdog(
+    IN  ULONG       Seconds
+    );
+
+XEN_API
+VOID
+SystemStopWatchdog(
+    VOID
+    );
+
 // VCPU
 
 __checkReturn
index 56cbcf7b3345fe603f64f731c923ac35eae9e0f0..11ca5224165040a35540d61aa44e86a5485b72ae 100644 (file)
@@ -51,7 +51,7 @@ __checkReturn
 XEN_API
 NTSTATUS
 SchedShutdownCode(
-    ULONG                   Reason
+    IN  ULONG               Reason
     )
 {
     struct sched_shutdown   op;
@@ -79,7 +79,7 @@ __checkReturn
 XEN_API
 NTSTATUS
 SchedShutdown(
-    ULONG                   Reason
+    IN  ULONG               Reason
     )
 {
     struct sched_shutdown   op;
@@ -119,3 +119,35 @@ SchedYield(
 {
     (VOID) SchedOp(SCHEDOP_yield, NULL);
 }
+
+XEN_API
+NTSTATUS
+SchedWatchdog(
+    IN OUT  PULONG          Id,
+    IN      ULONG           Seconds
+    )
+{
+    struct sched_watchdog   op;
+    LONG_PTR                rc;
+    NTSTATUS                status;
+
+    op.id = *Id;
+    op.timeout = Seconds;
+
+    rc = SchedOp(SCHEDOP_watchdog, &op);
+
+    if (rc < 0) {
+        ERRNO_TO_STATUS(-rc, status);
+        goto fail1;
+    }
+
+    if (*Id == 0)
+        *Id = (ULONG)rc;
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
index 45fe3b6c31bbfb6e111bb72b68806451947b3993..9f123595e509745cbfbcfea8918f5988bb90f1ab 100644 (file)
@@ -55,6 +55,11 @@ typedef struct _SYSTEM_PROCESSOR {
     UCHAR   ProcessorID;
 } SYSTEM_PROCESSOR, *PSYSTEM_PROCESSOR;
 
+typedef struct _SYSTEM_WATCHDOG {
+    ULONG   Id;
+    ULONG   Seconds;
+} SYSTEM_WATCHDOG, *PSYSTEM_WATCHDOG;
+
 typedef struct _SYSTEM_CONTEXT {
     LONG                References;
     PACPI_MADT          Madt;
@@ -64,6 +69,7 @@ typedef struct _SYSTEM_CONTEXT {
     PVOID               ProcessorChangeHandle;
     PHYSICAL_ADDRESS    MaximumPhysicalAddress;
     BOOLEAN             RealTimeIsUniversal;
+    SYSTEM_WATCHDOG     Watchdog;
 } SYSTEM_CONTEXT, *PSYSTEM_CONTEXT;
 
 static SYSTEM_CONTEXT   SystemContext;
@@ -1104,6 +1110,62 @@ SystemRealTimeIsUniversal(
     return Context->RealTimeIsUniversal;
 }
 
+XEN_API
+NTSTATUS
+SystemSetWatchdog(
+    IN  ULONG       Seconds
+    )
+{
+    PSYSTEM_CONTEXT Context = &SystemContext;
+    ULONG           Id = Context->Watchdog.Id;
+    NTSTATUS        status;
+
+    status = STATUS_INVALID_PARAMETER;
+    if (Seconds == 0)
+        goto fail1;
+
+    status = SchedWatchdog(&Id, Seconds);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    if (Context->Watchdog.Id == 0 || Context->Watchdog.Seconds != Seconds)
+        Info("%u: %us\n", Id, Seconds);
+
+    Context->Watchdog.Id = Id;
+    Context->Watchdog.Seconds = Seconds;
+    
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+XEN_API
+VOID
+SystemStopWatchdog(
+    VOID
+    )
+{
+    PSYSTEM_CONTEXT Context = &SystemContext;
+    NTSTATUS        status;
+
+    if (Context->Watchdog.Id == 0)
+        return;
+
+    status = SchedWatchdog(&Context->Watchdog.Id, 0);
+    ASSERT(NT_SUCCESS(status));
+
+    Info("%u\n", Context->Watchdog.Id);
+    
+    Context->Watchdog.Id = 0;
+    Context->Watchdog.Seconds = 0;
+}
+
 VOID
 SystemTeardown(
     VOID
index d59f06e9575dc055304c10c58661c64706e0fe2c..c03a45f70fd74597975f84028298477d26e0715e 100644 (file)
@@ -87,6 +87,7 @@ typedef struct _XENBUS_VIRQ {
     ULONG                   Cpu;
     PXENBUS_EVTCHN_CHANNEL  Channel;
     LARGE_INTEGER           TimeStamp;
+    ULONG                   Count;
 } XENBUS_VIRQ, *PXENBUS_VIRQ;
 
 struct _XENBUS_FDO {
@@ -152,7 +153,11 @@ struct _XENBUS_FDO {
     PXENBUS_RANGE_SET               RangeSet;
     LIST_ENTRY                      InterruptList;
 
+    ULONG                           Watchdog;
+
     LIST_ENTRY                      VirqList;
+    HIGH_LOCK                       VirqLock;
+
     PXENBUS_SUSPEND_CALLBACK        SuspendCallbackLate;
     PXENBUS_DEBUG_CALLBACK          DebugCallback;
     PLOG_DISPOSITION                LogDisposition;
@@ -2756,6 +2761,45 @@ FdoOutputBuffer(
                           (ULONG)(Cursor - FdoOutBuffer));
 }
 
+static FORCEINLINE BOOLEAN
+__FdoVirqPatWatchdog(
+    IN  PXENBUS_VIRQ    Virq
+    )
+{
+    PXENBUS_FDO         Fdo = Virq->Fdo;
+    ULONG               Cpu;
+    ULONG               Count;
+    BOOLEAN             Pat;
+    KIRQL               Irql;
+    PLIST_ENTRY         ListEntry;
+
+    AcquireHighLock(&Fdo->VirqLock, &Irql);
+    
+    Cpu = Virq->Cpu;
+    Count = Virq->Count++;
+    Pat = TRUE;
+
+    if (Virq->Count == 0) // wrapped
+        goto out;
+        
+    for (ListEntry = Fdo->VirqList.Flink;
+         ListEntry != &Fdo->VirqList;
+         ListEntry = ListEntry->Flink) {
+        Virq = CONTAINING_RECORD(ListEntry, XENBUS_VIRQ, ListEntry);
+
+        if (Virq->Type != VIRQ_TIMER || Virq->Cpu == Cpu)
+            continue;
+
+        if (Virq->Count <= Count)
+            Pat = FALSE;
+    }
+
+out:
+    ReleaseHighLock(&Fdo->VirqLock, Irql);
+
+    return Pat;
+}
+
 static
 _Function_class_(KSERVICE_ROUTINE)
 _IRQL_requires_(HIGH_LEVEL)
@@ -2782,6 +2826,9 @@ FdoVirqCallback(
         break;
 
     case VIRQ_TIMER:
+        if (__FdoVirqPatWatchdog(Virq))
+            SystemSetWatchdog(Fdo->Watchdog);
+
         break;
 
     default:
@@ -2792,8 +2839,6 @@ FdoVirqCallback(
     return TRUE;
 }
 
-#define XENBUS_TIMER_PERIOD 10
-
 static FORCEINLINE NTSTATUS
 __FdoVirqCreate(
     IN  PXENBUS_FDO     Fdo,
@@ -2803,6 +2848,7 @@ __FdoVirqCreate(
     )
 {
     PROCESSOR_NUMBER    ProcNumber;
+    unsigned int        vcpu_id;
     NTSTATUS            status;
 
     *Virq = __FdoAllocate(sizeof (XENBUS_VIRQ));
@@ -2835,15 +2881,21 @@ __FdoVirqCreate(
          ProcNumber.Group, ProcNumber.Number);
 
     if (Type == VIRQ_TIMER) {
-        unsigned int    vcpu_id;
         LARGE_INTEGER   Period;
 
         status = SystemVirtualCpuIndex(Cpu, &vcpu_id);
         ASSERT(NT_SUCCESS(status));
 
-        Period.QuadPart = TIME_S(XENBUS_TIMER_PERIOD);
+        BUG_ON(Fdo->Watchdog == 0);
+        Period.QuadPart = TIME_S(Fdo->Watchdog / 2);
 
-        (VOID) VcpuSetPeriodicTimer(vcpu_id, &Period);
+        status = VcpuSetPeriodicTimer(vcpu_id, &Period);
+        if (!NT_SUCCESS(status))
+            goto fail3;
+        
+        status = SystemSetWatchdog(Fdo->Watchdog);
+        if (!NT_SUCCESS(status))
+            goto fail4;
     }
 
     (VOID) XENBUS_EVTCHN(Unmask,
@@ -2854,10 +2906,22 @@ __FdoVirqCreate(
 
     return STATUS_SUCCESS;
 
+fail4:
+    Error("fail4\n");
+
+    (VOID) VcpuSetPeriodicTimer(vcpu_id, NULL);
+
+fail3:
+    Error("fail3\n");
+    
+    XENBUS_EVTCHN(Close,
+                  &Fdo->EvtchnInterface,
+                  (*Virq)->Channel);
+
 fail2:
     Error("fail2\n");
 
-    __FdoFree(Virq);
+    __FdoFree(*Virq);
 
 fail1:
     Error("fail1 (%08x)\n", status);
@@ -2877,6 +2941,8 @@ __FdoVirqDestroy(
     if (Virq->Type == VIRQ_TIMER) {
         unsigned int    vcpu_id;
         NTSTATUS        status;
+        
+        SystemStopWatchdog();
 
         status = SystemVirtualCpuIndex(Virq->Cpu, &vcpu_id);
         ASSERT(NT_SUCCESS(status));
@@ -2924,6 +2990,7 @@ FdoVirqInitialize(
     NTSTATUS            status;
 
     InitializeListHead(&Fdo->VirqList);
+    InitializeHighLock(&Fdo->VirqLock);
 
     status = __FdoVirqCreate(Fdo, VIRQ_DEBUG, 0, &Virq);
     if (!NT_SUCCESS(status))
@@ -2931,6 +2998,9 @@ FdoVirqInitialize(
 
     InsertTailList(&Fdo->VirqList, &Virq->ListEntry);
 
+    if (Fdo->Watchdog == 0)
+        goto done;
+
     Count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
 
     for (Index = 0; Index < Count; Index++) {
@@ -2945,6 +3015,7 @@ FdoVirqInitialize(
         InsertTailList(&Fdo->VirqList, &Virq->ListEntry);
     }
 
+done:
     return STATUS_SUCCESS;
 
 fail2:
@@ -5487,8 +5558,8 @@ __FdoFreeBuffer(
     Fdo->Buffer = NULL;
 }
 
-static BOOLEAN
-FdoIsBalloonEnabled(
+static NTSTATUS
+FdoBalloonInitialize(
     IN  PXENBUS_FDO Fdo
     )
 {
@@ -5498,8 +5569,6 @@ FdoIsBalloonEnabled(
     BOOLEAN         Enabled;
     NTSTATUS        status;
 
-    UNREFERENCED_PARAMETER(Fdo);
-
     Enabled = TRUE;
 
     status = RegistryQuerySystemStartOption(Key, &Option);
@@ -5514,7 +5583,53 @@ FdoIsBalloonEnabled(
     RegistryFreeSzValue(Option);
 
 done:
-    return Enabled;
+    return Enabled ?
+           BalloonInitialize(Fdo, &Fdo->BalloonContext) :
+           STATUS_SUCCESS;
+}
+
+static VOID
+FdoBalloonTeardown(
+    IN  PXENBUS_FDO Fdo
+    )
+{
+    if (Fdo->BalloonContext == NULL)
+        return;
+    
+    BalloonTeardown(Fdo->BalloonContext);
+    Fdo->BalloonContext = NULL;
+}
+
+static VOID
+FdoSetWatchdog(
+    IN  PXENBUS_FDO Fdo
+    )
+{
+    CHAR            Key[] = "XEN:WATCHDOG=";
+    PANSI_STRING    Option;
+    ULONG           Value;
+    NTSTATUS        status;
+
+    status = RegistryQuerySystemStartOption(Key, &Option);
+    if (!NT_SUCCESS(status))
+        return;
+
+    Value = strtoul(Option->Buffer + sizeof (Key) - 1, NULL, 0);
+
+    RegistryFreeSzValue(Option);
+
+    if (Value && Value < 10) {
+        Warning("%u < 10 (ROUNDING UP)\n");
+
+        Value = 10;
+    }
+
+    Fdo->Watchdog = Value;
+
+    if (Fdo->Watchdog != 0)
+        Info("WATCHDOG ENABLED (%us)\n", Fdo->Watchdog);
+    else
+        Info("WATCHDOG DISABLED\n");
 }
 
 NTSTATUS
@@ -5637,11 +5752,9 @@ FdoCreate(
     if (!NT_SUCCESS(status))
         goto fail19;
 
-    if (FdoIsBalloonEnabled(Fdo)) {
-        status = BalloonInitialize(Fdo, &Fdo->BalloonContext);
-        if (!NT_SUCCESS(status))
-            goto fail20;
-    }
+    status = FdoBalloonInitialize(Fdo);
+    if (!NT_SUCCESS(status))
+        goto fail20;
 
     status = DebugGetInterface(__FdoGetDebugContext(Fdo),
                                XENBUS_DEBUG_INTERFACE_VERSION_MAX,
@@ -5698,6 +5811,8 @@ done:
 
     (VOID) FdoSetFriendlyName(Fdo, Header.DeviceID);
 
+    FdoSetWatchdog(Fdo);
+
     Info("%p (%s) %s\n",
          FunctionDeviceObject,
          __FdoGetName(Fdo),
@@ -5882,10 +5997,7 @@ FdoDestroy(
         RtlZeroMemory(&Fdo->DebugInterface,
                       sizeof (XENBUS_DEBUG_INTERFACE));
 
-        if (Fdo->BalloonContext != NULL) {
-            BalloonTeardown(Fdo->BalloonContext);
-            Fdo->BalloonContext = NULL;
-        }
+        FdoBalloonTeardown(Fdo);
 
         UnplugTeardown(Fdo->UnplugContext);
         Fdo->UnplugContext = NULL;