3 * Copyright (C) 2011 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/mountmgr/notify.c
22 * PURPOSE: Mount Manager - Notifications handlers
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
24 * Alex Ionescu (alex.ionescu@reactos.org)
38 SendOnlineNotification(IN PUNICODE_STRING SymbolicName
)
43 PFILE_OBJECT FileObject
;
44 PIO_STACK_LOCATION Stack
;
45 PDEVICE_OBJECT DeviceObject
;
46 IO_STATUS_BLOCK IoStatusBlock
;
48 /* Get device object */
49 Status
= IoGetDeviceObjectPointer(SymbolicName
,
53 if (!NT_SUCCESS(Status
))
58 /* And attached device object */
59 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
61 /* And send VOLUME_ONLINE */
62 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
63 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_ONLINE
,
75 Stack
= IoGetNextIrpStackLocation(Irp
);
76 Stack
->FileObject
= FileObject
;
78 Status
= IoCallDriver(DeviceObject
, Irp
);
79 if (Status
== STATUS_PENDING
)
81 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
85 ObDereferenceObject(DeviceObject
);
86 ObDereferenceObject(FileObject
);
96 SendOnlineNotificationWorker(IN PVOID Parameter
)
100 PDEVICE_EXTENSION DeviceExtension
;
101 PONLINE_NOTIFICATION_WORK_ITEM WorkItem
;
102 PONLINE_NOTIFICATION_WORK_ITEM NewWorkItem
;
104 WorkItem
= (PONLINE_NOTIFICATION_WORK_ITEM
)Parameter
;
105 DeviceExtension
= WorkItem
->DeviceExtension
;
107 /* First, send the notification */
108 SendOnlineNotification(&(WorkItem
->SymbolicName
));
110 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
111 /* If there are no notifications running any longer, reset event */
112 if (--DeviceExtension
->OnlineNotificationCount
== 0)
114 KeSetEvent(&(DeviceExtension
->OnlineNotificationEvent
), 0, FALSE
);
117 /* If there are still notifications in queue */
118 if (!IsListEmpty(&(DeviceExtension
->OnlineNotificationListHead
)))
120 /* Queue a new one for execution */
121 Head
= RemoveHeadList(&(DeviceExtension
->OnlineNotificationListHead
));
122 NewWorkItem
= CONTAINING_RECORD(Head
, ONLINE_NOTIFICATION_WORK_ITEM
, List
);
123 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
124 NewWorkItem
->List
.Blink
= NULL
;
125 NewWorkItem
->List
.Flink
= NULL
;
126 ExQueueWorkItem((PWORK_QUEUE_ITEM
)NewWorkItem
, DelayedWorkQueue
);
131 DeviceExtension
->OnlineNotificationWorkerActive
= 0;
132 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
135 FreePool(WorkItem
->SymbolicName
.Buffer
);
145 PostOnlineNotification(IN PDEVICE_EXTENSION DeviceExtension
,
146 IN PUNICODE_STRING SymbolicName
)
149 PONLINE_NOTIFICATION_WORK_ITEM WorkItem
;
151 /* Allocate a notification work item */
152 WorkItem
= AllocatePool(sizeof(ONLINE_NOTIFICATION_WORK_ITEM
));
158 WorkItem
->List
.Flink
= NULL
;
159 WorkItem
->DeviceExtension
= DeviceExtension
;
160 WorkItem
->WorkerRoutine
= SendOnlineNotificationWorker
;
161 WorkItem
->Parameter
= WorkItem
;
162 WorkItem
->SymbolicName
.Length
= SymbolicName
->Length
;
163 WorkItem
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(WCHAR
);
164 WorkItem
->SymbolicName
.Buffer
= AllocatePool(WorkItem
->SymbolicName
.MaximumLength
);
165 if (!WorkItem
->SymbolicName
.Buffer
)
171 RtlCopyMemory(WorkItem
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
172 WorkItem
->SymbolicName
.Buffer
[SymbolicName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
174 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
175 DeviceExtension
->OnlineNotificationCount
++;
177 /* If no worker are active */
178 if (DeviceExtension
->OnlineNotificationWorkerActive
== 0)
180 /* Queue that one for execution */
181 DeviceExtension
->OnlineNotificationWorkerActive
= 1;
182 ExQueueWorkItem((PWORK_QUEUE_ITEM
)WorkItem
, DelayedWorkQueue
);
186 /* Otherwise, just put it in the queue list */
187 InsertTailList(&(DeviceExtension
->OnlineNotificationListHead
), &(WorkItem
->List
));
190 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
199 WaitForOnlinesToComplete(IN PDEVICE_EXTENSION DeviceExtension
)
203 KeInitializeEvent(&(DeviceExtension
->OnlineNotificationEvent
), NotificationEvent
, FALSE
);
205 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
207 /* Just wait all the worker are done */
208 if (DeviceExtension
->OnlineNotificationCount
!= 1)
210 DeviceExtension
->OnlineNotificationCount
--;
211 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
213 KeWaitForSingleObject(&(DeviceExtension
->OnlineNotificationEvent
),
219 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
220 DeviceExtension
->OnlineNotificationCount
++;
223 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
231 MountMgrTargetDeviceNotification(IN PVOID NotificationStructure
,
234 PDEVICE_EXTENSION DeviceExtension
;
235 PDEVICE_INFORMATION DeviceInformation
;
236 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
238 DeviceInformation
= Context
;
239 DeviceExtension
= DeviceInformation
->DeviceExtension
;
240 Notification
= NotificationStructure
;
242 /* If it's to signal that removal is complete, then, execute the function */
243 if (IsEqualGUID(&(Notification
->Event
), &GUID_TARGET_DEVICE_REMOVE_COMPLETE
))
245 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
247 /* It it's to signal that a volume has been mounted
248 * Verify if a database sync is required and execute it
250 else if (IsEqualGUID(&(Notification
->Event
), &GUID_IO_VOLUME_MOUNT
))
252 if (InterlockedCompareExchange(&(DeviceInformation
->MountState
),
256 InterlockedDecrement(&(DeviceInformation
->MountState
));
260 if (DeviceInformation
->NeedsReconcile
)
262 DeviceInformation
->NeedsReconcile
= FALSE
;
263 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
268 return STATUS_SUCCESS
;
275 RegisterForTargetDeviceNotification(IN PDEVICE_EXTENSION DeviceExtension
,
276 IN PDEVICE_INFORMATION DeviceInformation
)
279 PFILE_OBJECT FileObject
;
280 PDEVICE_OBJECT DeviceObject
;
282 /* Get device object */
283 Status
= IoGetDeviceObjectPointer(&(DeviceInformation
->DeviceName
),
284 FILE_READ_ATTRIBUTES
,
287 if (!NT_SUCCESS(Status
))
292 /* And simply register for notifications */
293 Status
= IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange
,
295 DeviceExtension
->DriverObject
,
296 MountMgrTargetDeviceNotification
,
298 &(DeviceInformation
->TargetDeviceNotificationEntry
));
299 if (!NT_SUCCESS(Status
))
301 DeviceInformation
->TargetDeviceNotificationEntry
= NULL
;
304 ObDereferenceObject(FileObject
);
313 MountMgrNotify(IN PDEVICE_EXTENSION DeviceExtension
)
318 PLIST_ENTRY NextEntry
;
320 /* Increase the epic number */
321 DeviceExtension
->EpicNumber
++;
323 InitializeListHead(&CopyList
);
325 /* Copy all the pending IRPs for notification */
326 IoAcquireCancelSpinLock(&OldIrql
);
327 while (!IsListEmpty(&(DeviceExtension
->IrpListHead
)))
329 NextEntry
= RemoveHeadList(&(DeviceExtension
->IrpListHead
));
330 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
331 InsertTailList(&CopyList
, &(Irp
->Tail
.Overlay
.ListEntry
));
333 IoReleaseCancelSpinLock(OldIrql
);
335 /* Then, notifiy them one by one */
336 while (!IsListEmpty(&CopyList
))
338 NextEntry
= RemoveHeadList(&CopyList
);
339 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
341 *((PULONG
)Irp
->AssociatedIrp
.SystemBuffer
) = DeviceExtension
->EpicNumber
;
342 Irp
->IoStatus
.Information
= sizeof(DeviceExtension
->EpicNumber
);
344 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
352 MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension
,
353 IN PUNICODE_STRING DeviceName
,
354 IN BOOLEAN ValidateVolume
)
359 PLIST_ENTRY NextEntry
;
360 PFILE_OBJECT FileObject
;
361 PIO_STACK_LOCATION Stack
;
362 PDEVICE_OBJECT DeviceObject
;
363 IO_STATUS_BLOCK IoStatusBlock
;
364 PDEVICE_RELATIONS DeviceRelations
;
365 PDEVICE_INFORMATION DeviceInformation
;
366 TARGET_DEVICE_CUSTOM_NOTIFICATION DeviceNotification
;
368 /* If we have to validate volume */
371 /* Then, ensure we can find the device */
372 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
373 while (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
375 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
376 if (RtlCompareUnicodeString(DeviceName
, &(DeviceInformation
->DeviceName
), TRUE
) == 0)
382 if (NextEntry
== &(DeviceExtension
->DeviceListHead
) ||
383 !DeviceInformation
->Volume
)
389 /* Then, get device object */
390 Status
= IoGetDeviceObjectPointer(DeviceName
,
391 FILE_READ_ATTRIBUTES
,
394 if (!NT_SUCCESS(Status
))
399 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
401 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
403 /* Set up empty IRP (yes, yes!) */
404 Irp
= IoBuildDeviceIoControlRequest(0,
415 ObDereferenceObject(DeviceObject
);
416 ObDereferenceObject(FileObject
);
420 Stack
= IoGetNextIrpStackLocation(Irp
);
422 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
423 Irp
->IoStatus
.Information
= 0;
425 /* Properly set it, we want to query device relations */
426 Stack
->MajorFunction
= IRP_MJ_PNP
;
427 Stack
->MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
428 Stack
->Parameters
.QueryDeviceRelations
.Type
= TargetDeviceRelation
;
429 Stack
->FileObject
= FileObject
;
431 /* And call driver */
432 Status
= IoCallDriver(DeviceObject
, Irp
);
433 if (Status
== STATUS_PENDING
)
435 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
436 Status
= IoStatusBlock
.Status
;
439 ObDereferenceObject(DeviceObject
);
440 ObDereferenceObject(FileObject
);
442 if (!NT_SUCCESS(Status
))
447 /* Validate device return */
448 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
449 if (DeviceRelations
->Count
< 1)
451 ExFreePool(DeviceRelations
);
455 DeviceObject
= DeviceRelations
->Objects
[0];
456 ExFreePool(DeviceRelations
);
458 /* Set up real notification */
459 DeviceNotification
.Version
= 1;
460 DeviceNotification
.Size
= sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION
);
461 DeviceNotification
.Event
= GUID_IO_VOLUME_NAME_CHANGE
;
462 DeviceNotification
.FileObject
= NULL
;
463 DeviceNotification
.NameBufferOffset
= -1;
466 IoReportTargetDeviceChangeAsynchronous(DeviceObject
,
470 ObDereferenceObject(DeviceObject
);
479 RemoveWorkItem(IN PUNIQUE_ID_WORK_ITEM WorkItem
)
481 PDEVICE_EXTENSION DeviceExtension
= WorkItem
->DeviceExtension
;
483 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
485 /* If even if being worked, it's too late */
488 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
489 KeSetEvent(WorkItem
->Event
, 0, FALSE
);
493 /* Otherwise, remove it from the list, and delete it */
494 RemoveEntryList(&(WorkItem
->UniqueIdWorkerItemListEntry
));
495 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
496 IoFreeIrp(WorkItem
->Irp
);
497 FreePool(WorkItem
->DeviceName
.Buffer
);
498 FreePool(WorkItem
->IrpBuffer
);
508 UniqueIdChangeNotifyWorker(IN PDEVICE_OBJECT DeviceObject
,
511 PUNIQUE_ID_WORK_ITEM WorkItem
= Context
;
512 PMOUNTDEV_UNIQUE_ID OldUniqueId
, NewUniqueId
;
513 PMOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT UniqueIdChange
;
515 UNREFERENCED_PARAMETER(DeviceObject
);
517 /* Validate worker */
518 if (!NT_SUCCESS(WorkItem
->Irp
->IoStatus
.Status
))
520 RemoveWorkItem(WorkItem
);
524 UniqueIdChange
= WorkItem
->Irp
->AssociatedIrp
.SystemBuffer
;
525 /* Get the old unique ID */
526 OldUniqueId
= AllocatePool(UniqueIdChange
->OldUniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
529 RemoveWorkItem(WorkItem
);
533 OldUniqueId
->UniqueIdLength
= UniqueIdChange
->OldUniqueIdLength
;
534 RtlCopyMemory(OldUniqueId
->UniqueId
,
535 (PVOID
)((ULONG_PTR
)UniqueIdChange
+ UniqueIdChange
->OldUniqueIdOffset
),
536 UniqueIdChange
->OldUniqueIdLength
);
538 /* Get the new unique ID */
539 NewUniqueId
= AllocatePool(UniqueIdChange
->NewUniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
542 FreePool(OldUniqueId
);
543 RemoveWorkItem(WorkItem
);
547 NewUniqueId
->UniqueIdLength
= UniqueIdChange
->NewUniqueIdLength
;
548 RtlCopyMemory(NewUniqueId
->UniqueId
,
549 (PVOID
)((ULONG_PTR
)UniqueIdChange
+ UniqueIdChange
->NewUniqueIdOffset
),
550 UniqueIdChange
->NewUniqueIdLength
);
552 /* Call the real worker */
553 MountMgrUniqueIdChangeRoutine(WorkItem
->DeviceExtension
, OldUniqueId
, NewUniqueId
);
554 IssueUniqueIdChangeNotifyWorker(WorkItem
, NewUniqueId
);
556 FreePool(NewUniqueId
);
557 FreePool(OldUniqueId
);
567 UniqueIdChangeNotifyCompletion(IN PDEVICE_OBJECT DeviceObject
,
571 PUNIQUE_ID_WORK_ITEM WorkItem
= Context
;
573 UNREFERENCED_PARAMETER(DeviceObject
);
574 UNREFERENCED_PARAMETER(Irp
);
576 /* Simply queue the work item */
577 IoQueueWorkItem(WorkItem
->WorkItem
,
578 UniqueIdChangeNotifyWorker
,
582 return STATUS_MORE_PROCESSING_REQUIRED
;
589 IssueUniqueIdChangeNotifyWorker(IN PUNIQUE_ID_WORK_ITEM WorkItem
,
590 IN PMOUNTDEV_UNIQUE_ID UniqueId
)
594 PFILE_OBJECT FileObject
;
595 PIO_STACK_LOCATION Stack
;
596 PDEVICE_OBJECT DeviceObject
;
598 /* Get the device object */
599 Status
= IoGetDeviceObjectPointer(&(WorkItem
->DeviceName
),
600 FILE_READ_ATTRIBUTES
,
603 if (!NT_SUCCESS(Status
))
605 RemoveWorkItem(WorkItem
);
609 /* And then, the attached device */
610 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
612 /* Initialize the IRP */
614 IoInitializeIrp(Irp
, IoSizeOfIrp(WorkItem
->StackSize
), (CCHAR
)WorkItem
->StackSize
);
616 if (InterlockedExchange((PLONG
)&(WorkItem
->Event
), 0) != 0)
618 ObDereferenceObject(FileObject
);
619 ObDereferenceObject(DeviceObject
);
620 RemoveWorkItem(WorkItem
);
624 Irp
->AssociatedIrp
.SystemBuffer
= WorkItem
->IrpBuffer
;
625 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
626 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, UniqueId
, UniqueId
->UniqueIdLength
+ sizeof(USHORT
));
628 Stack
= IoGetNextIrpStackLocation(Irp
);
630 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
= UniqueId
->UniqueIdLength
+ sizeof(USHORT
);
631 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
= WorkItem
->IrpBufferLength
;
632 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= 0;
633 Stack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY
;
634 Stack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
636 Status
= IoSetCompletionRoutineEx(WorkItem
->DeviceExtension
->DeviceObject
,
638 UniqueIdChangeNotifyCompletion
,
641 if (!NT_SUCCESS(Status
))
643 ObDereferenceObject(FileObject
);
644 ObDereferenceObject(DeviceObject
);
645 RemoveWorkItem(WorkItem
);
649 /* Call the driver */
650 IoCallDriver(DeviceObject
, Irp
);
651 ObDereferenceObject(FileObject
);
652 ObDereferenceObject(DeviceObject
);
659 IssueUniqueIdChangeNotify(IN PDEVICE_EXTENSION DeviceExtension
,
660 IN PUNICODE_STRING DeviceName
,
661 IN PMOUNTDEV_UNIQUE_ID UniqueId
)
664 PVOID IrpBuffer
= NULL
;
665 PFILE_OBJECT FileObject
;
666 PDEVICE_OBJECT DeviceObject
;
667 PUNIQUE_ID_WORK_ITEM WorkItem
= NULL
;
669 /* Get the associated device object */
670 Status
= IoGetDeviceObjectPointer(DeviceName
,
671 FILE_READ_ATTRIBUTES
,
674 if (!NT_SUCCESS(Status
))
679 /* And then, get attached device */
680 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
682 ObDereferenceObject(FileObject
);
684 /* Allocate a work item */
685 WorkItem
= AllocatePool(sizeof(UNIQUE_ID_WORK_ITEM
));
688 ObDereferenceObject(DeviceObject
);
692 WorkItem
->Event
= NULL
;
693 WorkItem
->WorkItem
= IoAllocateWorkItem(DeviceExtension
->DeviceObject
);
694 if (!WorkItem
->WorkItem
)
696 ObDereferenceObject(DeviceObject
);
700 WorkItem
->DeviceExtension
= DeviceExtension
;
701 WorkItem
->StackSize
= DeviceObject
->StackSize
;
702 /* Already provide the IRP */
703 WorkItem
->Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
705 ObDereferenceObject(DeviceObject
);
712 /* Ensure it has enough space */
713 IrpBuffer
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT
) + 1024);
719 WorkItem
->DeviceName
.Length
= DeviceName
->Length
;
720 WorkItem
->DeviceName
.MaximumLength
= DeviceName
->Length
+ sizeof(WCHAR
);
721 WorkItem
->DeviceName
.Buffer
= AllocatePool(WorkItem
->DeviceName
.MaximumLength
);
722 if (!WorkItem
->DeviceName
.Buffer
)
727 RtlCopyMemory(WorkItem
->DeviceName
.Buffer
, DeviceName
->Buffer
, DeviceName
->Length
);
728 WorkItem
->DeviceName
.Buffer
[DeviceName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
730 WorkItem
->IrpBuffer
= IrpBuffer
;
731 WorkItem
->IrpBufferLength
= sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT
) + 1024;
733 /* Add the worker in the list */
734 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
735 InsertHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
), &(WorkItem
->UniqueIdWorkerItemListEntry
));
736 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
738 /* And call the worker */
739 IssueUniqueIdChangeNotifyWorker(WorkItem
, UniqueId
);
751 IoFreeIrp(WorkItem
->Irp
);
754 if (WorkItem
->WorkItem
)
756 IoFreeWorkItem(WorkItem
->WorkItem
);