summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWei Mao <[email protected]>2018-01-12 13:55:09 -0800
committerWei Mao <[email protected]>2018-01-12 13:58:14 -0800
commitac371a73a94bbe20a8bcfec51b44205c7374f0f5 (patch)
treeb1c949efb6f9302591a770ffd90f7195112139f2
parent80e1fd60244b1e339e75dc6ae43766f1b5c73dd9 (diff)
general/toaster/toastmon: stop iotarget/timer on d0exit
Bucket IDs: - 0x10d_5_vrf_wdftoastmon!toastmon_readrequestcompletionroutine - AV_VRF_Wdf01000!FxRequestBase::Vf_VerifyDispose - AV_VRF_wdftoastmon!Toastmon_EvtTimerPostRequests WDF verifier breaks: - Driver is trying to delete WDFREQUEST while it is still active on WDFIOTARGET - Calling WdfTimerStart when the timer object is running down will lead to a crash - WDFREQUEST already sent to a target
-rw-r--r--general/toaster/toastDrv/kmdf/toastmon/toastmon.H10
-rw-r--r--general/toaster/toastDrv/kmdf/toastmon/toastmon.c198
-rw-r--r--general/toaster/toastDrv/kmdf/toastmon/wmi.c4
3 files changed, 149 insertions, 63 deletions
diff --git a/general/toaster/toastDrv/kmdf/toastmon/toastmon.H b/general/toaster/toastDrv/kmdf/toastmon/toastmon.H
index 62a986a8..68b6fdce 100644
--- a/general/toaster/toastDrv/kmdf/toastmon/toastmon.H
+++ b/general/toaster/toastDrv/kmdf/toastmon/toastmon.H
@@ -44,14 +44,6 @@ typedef struct _TARGET_DEVICE_INFO {
WDFREQUEST WriteRequest;
WDFTIMER TimerForPostingRequests;
- //
- // Set to TRUE while the target is opened. Will be set to FALSE at query remove (for a graceful remove)
- // or removal complete (surprise removal of the target). Can be set back to TRUE if the graceful remove
- // fails and the query remove is canceled.
- //
- // Guarded by DeviceExtension->TargetDeviceCollectionLock
- //
- BOOLEAN Opened;
} TARGET_DEVICE_INFO, *PTARGET_DEVICE_INFO;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(TARGET_DEVICE_INFO, GetTargetDeviceInfo)
@@ -71,6 +63,8 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(TIMER_CONTEXT, GetTimerContext)
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD ToastMon_EvtDeviceAdd;
EVT_WDF_DEVICE_CONTEXT_CLEANUP ToastMon_EvtDeviceContextCleanup;
+EVT_WDF_DEVICE_D0_ENTRY ToastMon_EvtDeviceD0Entry;
+EVT_WDF_DEVICE_D0_EXIT ToastMon_EvtDeviceD0Exit;
EVT_WDF_IO_TARGET_QUERY_REMOVE ToastMon_EvtIoTargetQueryRemove;
EVT_WDF_IO_TARGET_REMOVE_CANCELED ToastMon_EvtIoTargetRemoveCanceled;
EVT_WDF_IO_TARGET_REMOVE_COMPLETE ToastMon_EvtIoTargetRemoveComplete;
diff --git a/general/toaster/toastDrv/kmdf/toastmon/toastmon.c b/general/toaster/toastDrv/kmdf/toastmon/toastmon.c
index f140e9d7..c011c73e 100644
--- a/general/toaster/toastDrv/kmdf/toastmon/toastmon.c
+++ b/general/toaster/toastDrv/kmdf/toastmon/toastmon.c
@@ -38,6 +38,7 @@ Environment:
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, ToastMon_EvtDeviceAdd)
#pragma alloc_text (PAGE, ToastMon_EvtDeviceContextCleanup)
+#pragma alloc_text (PAGE, ToastMon_EvtDeviceD0Exit)
#pragma alloc_text (PAGE, ToastMon_PnpNotifyInterfaceChange)
#pragma alloc_text (PAGE, ToastMon_EvtIoTargetQueryRemove)
#pragma alloc_text (PAGE, ToastMon_EvtIoTargetRemoveCanceled)
@@ -135,6 +136,7 @@ Return Value:
{
WDF_OBJECT_ATTRIBUTES attributes;
NTSTATUS status = STATUS_SUCCESS;
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks;
WDFDEVICE device;
PDEVICE_EXTENSION deviceExtension;
@@ -152,6 +154,12 @@ Return Value:
attributes.EvtCleanupCallback = ToastMon_EvtDeviceContextCleanup;
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks);
+ pnpCallbacks.EvtDeviceD0Entry = ToastMon_EvtDeviceD0Entry;
+ pnpCallbacks.EvtDeviceD0Exit = ToastMon_EvtDeviceD0Exit;
+
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks);
+
//
// Create a framework device object.This call will inturn create
// a WDM deviceobject, attach to the lower stack and set the
@@ -290,6 +298,105 @@ Return Value:
_Use_decl_annotations_
NTSTATUS
+ToastMon_EvtDeviceD0Entry(
+ WDFDEVICE Device,
+ WDF_POWER_DEVICE_STATE PreviousState
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceD0Entry performs operations that are needed when the driver's
+ device enters the D0 power state.
+
+ EvtDeviceD0Entry should not be marked as Pageable.
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension;
+ PTARGET_DEVICE_INFO targetDeviceInfo;
+ WDFIOTARGET ioTarget;
+ ULONG count, i;
+
+ UNREFERENCED_PARAMETER(PreviousState);
+
+ KdPrint( ("ToastMon_EvtDeviceD0Entry\n"));
+
+ deviceExtension = GetDeviceExtension((WDFDEVICE)Device);
+
+ //
+ // (Re-)Start IoTarget and timers
+ //
+
+ WdfWaitLockAcquire(deviceExtension->TargetDeviceCollectionLock, NULL);
+
+ count = WdfCollectionGetCount(deviceExtension->TargetDeviceCollection);
+ for (i = 0; i < count; i ++) {
+
+ ioTarget = WdfCollectionGetItem(deviceExtension->TargetDeviceCollection, i);
+ WdfIoTargetStart(ioTarget);
+
+ targetDeviceInfo = GetTargetDeviceInfo(ioTarget);
+ WdfTimerStart(targetDeviceInfo->TimerForPostingRequests,
+ WDF_REL_TIMEOUT_IN_MS(1));
+ }
+
+ WdfWaitLockRelease(deviceExtension->TargetDeviceCollectionLock);
+
+ return STATUS_SUCCESS;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+ToastMon_EvtDeviceD0Exit(
+ WDFDEVICE Device,
+ WDF_POWER_DEVICE_STATE TargetState
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceD0Exit performs operations that are needed when the driver's
+ device leaves the D0 power state.
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension;
+ PTARGET_DEVICE_INFO targetDeviceInfo;
+ WDFIOTARGET ioTarget;
+ ULONG count, i;
+
+ UNREFERENCED_PARAMETER(TargetState);
+
+ PAGED_CODE();
+
+ KdPrint( ("ToastMon_EvtDeviceD0Exit\n"));
+
+ deviceExtension = GetDeviceExtension((WDFDEVICE)Device);
+
+ //
+ // Stop IoTarget and timers
+ //
+
+ WdfWaitLockAcquire(deviceExtension->TargetDeviceCollectionLock, NULL);
+
+ count = WdfCollectionGetCount(deviceExtension->TargetDeviceCollection);
+ for (i = 0; i < count; i ++) {
+
+ ioTarget = WdfCollectionGetItem(deviceExtension->TargetDeviceCollection, i);
+ WdfIoTargetStop(ioTarget, WdfIoTargetWaitForSentIoToComplete);
+
+ targetDeviceInfo = GetTargetDeviceInfo(ioTarget);
+ WdfTimerStop(targetDeviceInfo->TimerForPostingRequests, TRUE);
+ }
+
+ WdfWaitLockRelease(deviceExtension->TargetDeviceCollectionLock);
+
+ return STATUS_SUCCESS;
+}
+
+_Use_decl_annotations_
+NTSTATUS
ToastMon_PnpNotifyInterfaceChange(
PVOID NotificationStruct,
PVOID Context
@@ -567,13 +674,6 @@ Return Value:
WdfTimerStart(targetDeviceInfo->TimerForPostingRequests,
WDF_REL_TIMEOUT_IN_MS(1));
- //
- // Can be set outside of holding TargetDeviceCollectionLock because we are
- // creating the target in a notification callback and all subsequent state changes notifications
- // can only happen after the arrival notification returns back to the kernel
- //
- targetDeviceInfo->Opened = TRUE;
-
*Target = ioTarget;
return status;
@@ -606,7 +706,6 @@ Return Value:
--*/
{
PTARGET_DEVICE_INFO targetDeviceInfo;
- WDFWAITLOCK targetDeviceCollectionLock;
PAGED_CODE();
@@ -620,15 +719,6 @@ Return Value:
WdfTimerStop(targetDeviceInfo->TimerForPostingRequests, TRUE);
- targetDeviceCollectionLock = targetDeviceInfo->DeviceExtension->TargetDeviceCollectionLock;
-
- //
- // The target is being query removed, set Opened to FALSE to match this state change.
- //
- WdfWaitLockAcquire(targetDeviceCollectionLock, NULL);
- targetDeviceInfo->Opened = FALSE;
- WdfWaitLockRelease(targetDeviceCollectionLock);
-
WdfIoTargetCloseForQueryRemove(IoTarget);
return STATUS_SUCCESS;
@@ -657,7 +747,6 @@ Return Value:
--*/
{
PTARGET_DEVICE_INFO targetDeviceInfo;
- WDFWAITLOCK targetDeviceCollectionLock;
WDF_IO_TARGET_OPEN_PARAMS openParams;
NTSTATUS status;
@@ -680,16 +769,6 @@ Return Value:
return;
}
- targetDeviceCollectionLock = targetDeviceInfo->DeviceExtension->TargetDeviceCollectionLock;
-
- //
- // The query remove has failed and the target has been successfully reopened. Set Opened
- // back to TRUE to reflect the state change.
- //
- WdfWaitLockAcquire(targetDeviceCollectionLock, NULL);
- targetDeviceInfo->Opened = TRUE;
- WdfWaitLockRelease(targetDeviceCollectionLock);
-
//
// Restart the timer.
//
@@ -733,14 +812,11 @@ Return Value:
WdfTimerStop(targetDeviceInfo->TimerForPostingRequests, TRUE);
//
- // Remove the target device from the collection and set Opened to FALSE to match
- // the state change (in the case of a surprise removal of the target,
- // ToastMon_EvtIoTargetQueryRemove is not called so Opened is still TRUE).
+ // Remove the target device from the collection
//
WdfWaitLockAcquire(deviceExtension->TargetDeviceCollectionLock, NULL);
WdfCollectionRemove(deviceExtension->TargetDeviceCollection, IoTarget);
- targetDeviceInfo->Opened = FALSE;
WdfWaitLockRelease(deviceExtension->TargetDeviceCollectionLock);
@@ -827,7 +903,17 @@ Return Value:
targetInfo = GetTargetDeviceInfo(IoTarget);
- request = targetInfo->ReadRequest;
+ //
+ // Clear the ReadRequest field in the context to avoid
+ // being reposted even before the reqeuest completes.
+ // This will be reset in the complete routine when the request completes.
+ //
+ request = InterlockedExchangePointer(&targetInfo->ReadRequest, NULL);
+ if (request == NULL) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ KdPrint(("Request is already posted\n", status));
+ goto exit;
+ }
//
// Allocate memory for read. Ideally I should have allocated the memory upfront along
@@ -848,7 +934,7 @@ Return Value:
if (!NT_SUCCESS(status)) {
KdPrint(("WdfMemoryCreate failed 0x%x\n", status));
- return status;
+ goto exit;
}
status = WdfIoTargetFormatRequestForRead(
@@ -859,26 +945,23 @@ Return Value:
NULL); // OutputBufferOffset
if (!NT_SUCCESS(status)) {
KdPrint(("WdfIoTargetFormatRequestForRead failed 0x%x\n", status));
- return status;
+ goto exit;
}
WdfRequestSetCompletionRoutine(request,
Toastmon_ReadRequestCompletionRoutine,
targetInfo);
- //
- // Clear the ReadRequest field in the context to avoid
- // being reposted even before the reqeuest completes.
- // This will be reset in the complete routine when the request completes.
- //
- targetInfo->ReadRequest = NULL;
-
if(WdfRequestSend(request, IoTarget, WDF_NO_SEND_OPTIONS) == FALSE) {
status = WdfRequestGetStatus(request);
KdPrint(("WdfRequestSend failed 0x%x\n", status));
- targetInfo->ReadRequest = request;
+ goto exit;
}
+exit:
+ if (!NT_SUCCESS(status)) {
+ targetInfo->ReadRequest = request;
+ }
return status;
}
@@ -907,7 +990,17 @@ Return Value:
targetInfo = GetTargetDeviceInfo(IoTarget);
- request = targetInfo->WriteRequest;
+ //
+ // Clear the Write field in the context to avoid
+ // being reposted even before the reqeuest completes.
+ // This will be reset in the complete routine when the request completes.
+ //
+ request = InterlockedExchangePointer(&targetInfo->WriteRequest, NULL);
+ if (request == NULL) {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ KdPrint(("Request is already posted\n", status));
+ goto exit;
+ }
//
// Allocate memory for write. Ideally I should have allocated the memory upfront along
@@ -928,7 +1021,7 @@ Return Value:
if (!NT_SUCCESS(status)) {
KdPrint(("WdfMemoryCreate failed 0x%x\n", status));
- return status;
+ goto exit;
}
status = WdfIoTargetFormatRequestForWrite(
@@ -939,26 +1032,23 @@ Return Value:
NULL); // OutputBufferOffset
if (!NT_SUCCESS(status)) {
KdPrint(("WdfIoTargetFormatRequestForWrite failed 0x%x\n", status));
- return status;
+ goto exit;
}
WdfRequestSetCompletionRoutine(request,
Toastmon_WriteRequestCompletionRoutine,
targetInfo);
- //
- // Clear the WriteRequest field in the context to avoid
- // being reposted even before the reqeuest completes.
- // This will be reset in the complete routine when the request completes.
- //
- targetInfo->WriteRequest = NULL;
-
if(WdfRequestSend(request, IoTarget, WDF_NO_SEND_OPTIONS) == FALSE) {
status = WdfRequestGetStatus(request);
KdPrint(("WdfRequestSend failed 0x%x\n", status));
- targetInfo->WriteRequest = request;
+ goto exit;
}
+exit:
+ if (!NT_SUCCESS(status)) {
+ targetInfo->WriteRequest = request;
+ }
return status;
}
diff --git a/general/toaster/toastDrv/kmdf/toastmon/wmi.c b/general/toaster/toastDrv/kmdf/toastmon/wmi.c
index 8d8b4406..eb0e8e70 100644
--- a/general/toaster/toastDrv/kmdf/toastmon/wmi.c
+++ b/general/toaster/toastDrv/kmdf/toastmon/wmi.c
@@ -178,6 +178,7 @@ Return Value:
PDEVICE_EXTENSION deviceExt = Context;
WDFCOLLECTION hCollection = deviceExt->TargetDeviceCollection;
WDFIOTARGET ioTarget;
+ WDF_IO_TARGET_STATE ioTargetState;
ULONG i;
PAGED_CODE();
@@ -193,7 +194,8 @@ Return Value:
// The WdfIoTargetWdmGetXxxDeviceObject APIs can only be called while the target is opened, otherwise
// they can return undefined values.
//
- if (GetTargetDeviceInfo(ioTarget)->Opened == FALSE) {
+ ioTargetState = WdfIoTargetGetState(ioTarget);
+ if (ioTargetState != WdfIoTargetStarted) {
KdPrint(("WDFIOTARGET %p not in an opened state.\n", ioTarget));
continue;
}