From 9c15277aa6ac0cb44d6d40279671d00443e6520e Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Fri, 29 Nov 2024 19:01:28 +0200 Subject: [PATCH] netkvm: fix BSOD if some queue fails to renew https://issues.redhat.com/browse/RHEL-68725 https://github.com/virtio-win/kvm-guest-drivers-windows/issues/1197 In such case we do not have any other option than request to unload the driver. This can happen in 2 flows: power up (during fast startup) or reset, both with driver verifier that simulates low resources. In reset flow we need to request driver unload explicitly. Power up flow works in SET_POWER, so it will do it automatically. Signed-off-by: Yuri Benditovich --- NetKVM/Common/ParaNdis-AbstractPath.h | 3 ++- NetKVM/Common/ParaNdis_Common.cpp | 13 +++++++++---- NetKVM/wlh/ParaNdis6_Driver.cpp | 11 +++++++++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/NetKVM/Common/ParaNdis-AbstractPath.h b/NetKVM/Common/ParaNdis-AbstractPath.h index 9d2bb3289..1bd90d409 100644 --- a/NetKVM/Common/ParaNdis-AbstractPath.h +++ b/NetKVM/Common/ParaNdis-AbstractPath.h @@ -49,9 +49,10 @@ class CParaNdisAbstractPath m_pVirtQueue->EnableInterrupts(); } - void Renew() + bool Renew() { m_pVirtQueue->Renew(); + return m_pVirtQueue->IsValid(); } ULONG getCPUIndex(); diff --git a/NetKVM/Common/ParaNdis_Common.cpp b/NetKVM/Common/ParaNdis_Common.cpp index 40359acd7..9096fafb0 100755 --- a/NetKVM/Common/ParaNdis_Common.cpp +++ b/NetKVM/Common/ParaNdis_Common.cpp @@ -2088,7 +2088,7 @@ ParaNdis_UpdateMAC(PARANDIS_ADAPTER *pContext) NDIS_STATUS ParaNdis_PowerOn(PARANDIS_ADAPTER *pContext) { UINT i; - + bool bRenewed = true; DEBUG_ENTRY(0); ParaNdis_DebugHistory(pContext, _etagHistoryLogOperation::hopPowerOn, NULL, 1, 0, 0); @@ -2109,12 +2109,17 @@ NDIS_STATUS ParaNdis_PowerOn(PARANDIS_ADAPTER *pContext) for (i = 0; i < pContext->nPathBundles; i++) { - pContext->pPathBundles[i].txPath.Renew(); - pContext->pPathBundles[i].rxPath.Renew(); + bRenewed = bRenewed && pContext->pPathBundles[i].txPath.Renew(); + bRenewed = bRenewed && pContext->pPathBundles[i].rxPath.Renew(); } if (pContext->bCXPathCreated) { - pContext->CXPath.Renew(); + bRenewed = bRenewed && pContext->CXPath.Renew(); + } + + if (!bRenewed) { + DPrintf(0, "[%s] one or more queues failed to renew\n", __FUNCTION__); + return NDIS_STATUS_RESOURCES; } ParaNdis_RestoreDeviceConfigurationAfterReset(pContext); diff --git a/NetKVM/wlh/ParaNdis6_Driver.cpp b/NetKVM/wlh/ParaNdis6_Driver.cpp index 849eb661b..141b9503c 100755 --- a/NetKVM/wlh/ParaNdis6_Driver.cpp +++ b/NetKVM/wlh/ParaNdis6_Driver.cpp @@ -553,12 +553,19 @@ static NDIS_STATUS ParaNdis6_Reset( NDIS_HANDLE miniportAdapterContext, PBOOLEAN pAddressingReset) { + NDIS_STATUS status; PARANDIS_ADAPTER *pContext = (PARANDIS_ADAPTER *)miniportAdapterContext; DEBUG_ENTRY(0); ParaNdis_PowerOff(pContext); - ParaNdis_PowerOn(pContext); + status = ParaNdis_PowerOn(pContext); *pAddressingReset = FALSE; - return NDIS_STATUS_SUCCESS; + // if ParaNdis_PowerOn fails, just returning error + // does not help, so request unload + if (!NT_SUCCESS(status)) { + DPrintf(0, "[%s] requesting removal\n", __FUNCTION__); + NdisMRemoveMiniport(pContext->MiniportHandle); + } + return status; } /***************************************************