From: Paul Durrant Date: Wed, 18 Nov 2020 15:57:44 +0000 (+0000) Subject: watchdog X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=refs%2Fheads%2Fwatchdog;p=people%2Fpauldu%2Fxenbus.git watchdog Signed-off-by: Paul Durrant --- diff --git a/include/xen.h b/include/xen.h index 4698a33..7371a2b 100644 --- a/include/xen.h +++ b/include/xen.h @@ -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 diff --git a/src/xen/sched.c b/src/xen/sched.c index 56cbcf7..11ca522 100644 --- a/src/xen/sched.c +++ b/src/xen/sched.c @@ -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; +} diff --git a/src/xen/system.c b/src/xen/system.c index 45fe3b6..9f12359 100644 --- a/src/xen/system.c +++ b/src/xen/system.c @@ -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 diff --git a/src/xenbus/fdo.c b/src/xenbus/fdo.c index d59f06e..c03a45f 100644 --- a/src/xenbus/fdo.c +++ b/src/xenbus/fdo.c @@ -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;