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
, WorkItem
.List
);
123 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
124 NewWorkItem
->WorkItem
.List
.Blink
= NULL
;
125 NewWorkItem
->WorkItem
.List
.Flink
= NULL
;
126 ExQueueWorkItem(&NewWorkItem
->WorkItem
, 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 ExInitializeWorkItem(&WorkItem
->WorkItem
, SendOnlineNotificationWorker
, WorkItem
);
159 WorkItem
->DeviceExtension
= DeviceExtension
;
160 WorkItem
->SymbolicName
.Length
= SymbolicName
->Length
;
161 WorkItem
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(WCHAR
);
162 WorkItem
->SymbolicName
.Buffer
= AllocatePool(WorkItem
->SymbolicName
.MaximumLength
);
163 if (!WorkItem
->SymbolicName
.Buffer
)
169 RtlCopyMemory(WorkItem
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
170 WorkItem
->SymbolicName
.Buffer
[SymbolicName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
172 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
173 DeviceExtension
->OnlineNotificationCount
++;
175 /* If no worker are active */
176 if (DeviceExtension
->OnlineNotificationWorkerActive
== 0)
178 /* Queue that one for execution */
179 DeviceExtension
->OnlineNotificationWorkerActive
= 1;
180 ExQueueWorkItem(&WorkItem
->WorkItem
, DelayedWorkQueue
);
184 /* Otherwise, just put it in the queue list */
185 InsertTailList(&(DeviceExtension
->OnlineNotificationListHead
), &(WorkItem
->WorkItem
.List
));
188 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
197 WaitForOnlinesToComplete(IN PDEVICE_EXTENSION DeviceExtension
)
201 KeInitializeEvent(&(DeviceExtension
->OnlineNotificationEvent
), NotificationEvent
, FALSE
);
203 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
205 /* Just wait all the worker are done */
206 if (DeviceExtension
->OnlineNotificationCount
!= 1)
208 DeviceExtension
->OnlineNotificationCount
--;
209 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
211 KeWaitForSingleObject(&(DeviceExtension
->OnlineNotificationEvent
),
217 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
218 DeviceExtension
->OnlineNotificationCount
++;
221 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
229 MountMgrTargetDeviceNotification(IN PVOID NotificationStructure
,
232 PDEVICE_EXTENSION DeviceExtension
;
233 PDEVICE_INFORMATION DeviceInformation
;
234 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
236 DeviceInformation
= Context
;
237 DeviceExtension
= DeviceInformation
->DeviceExtension
;
238 Notification
= NotificationStructure
;
240 /* If it's to signal that removal is complete, then, execute the function */
241 if (IsEqualGUID(&(Notification
->Event
), &GUID_TARGET_DEVICE_REMOVE_COMPLETE
))
243 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
245 /* It it's to signal that a volume has been mounted
246 * Verify if a database sync is required and execute it
248 else if (IsEqualGUID(&(Notification
->Event
), &GUID_IO_VOLUME_MOUNT
))
250 /* If we were already mounted, then mark us unmounted */
251 if (InterlockedCompareExchange(&(DeviceInformation
->MountState
),
255 InterlockedDecrement(&(DeviceInformation
->MountState
));
257 /* Otherwise, start mounting the device and first, reconcile its DB if required */
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, notify 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 /* No need to notify for a PnP device or if we didn't find the device */
383 if (NextEntry
== &(DeviceExtension
->DeviceListHead
) ||
384 !DeviceInformation
->ManuallyRegistered
)
390 /* Then, get device object */
391 Status
= IoGetDeviceObjectPointer(DeviceName
,
392 FILE_READ_ATTRIBUTES
,
395 if (!NT_SUCCESS(Status
))
400 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
402 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
404 /* Set up empty IRP (yes, yes!) */
405 Irp
= IoBuildDeviceIoControlRequest(0,
416 ObDereferenceObject(DeviceObject
);
417 ObDereferenceObject(FileObject
);
421 Stack
= IoGetNextIrpStackLocation(Irp
);
423 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
424 Irp
->IoStatus
.Information
= 0;
426 /* Properly set it, we want to query device relations */
427 Stack
->MajorFunction
= IRP_MJ_PNP
;
428 Stack
->MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
429 Stack
->Parameters
.QueryDeviceRelations
.Type
= TargetDeviceRelation
;
430 Stack
->FileObject
= FileObject
;
432 /* And call driver */
433 Status
= IoCallDriver(DeviceObject
, Irp
);
434 if (Status
== STATUS_PENDING
)
436 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
437 Status
= IoStatusBlock
.Status
;
440 ObDereferenceObject(DeviceObject
);
441 ObDereferenceObject(FileObject
);
443 if (!NT_SUCCESS(Status
))
448 /* Validate device return */
449 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
450 if (DeviceRelations
->Count
< 1)
452 ExFreePool(DeviceRelations
);
456 DeviceObject
= DeviceRelations
->Objects
[0];
457 ExFreePool(DeviceRelations
);
459 /* Set up real notification */
460 DeviceNotification
.Version
= 1;
461 DeviceNotification
.Size
= sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION
);
462 DeviceNotification
.Event
= GUID_IO_VOLUME_NAME_CHANGE
;
463 DeviceNotification
.FileObject
= NULL
;
464 DeviceNotification
.NameBufferOffset
= -1;
467 IoReportTargetDeviceChangeAsynchronous(DeviceObject
,
471 ObDereferenceObject(DeviceObject
);
480 RemoveWorkItem(IN PUNIQUE_ID_WORK_ITEM WorkItem
)
482 PDEVICE_EXTENSION DeviceExtension
= WorkItem
->DeviceExtension
;
484 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
486 /* If even if being worked, it's too late */
489 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
490 KeSetEvent(WorkItem
->Event
, 0, FALSE
);
494 /* Otherwise, remove it from the list, and delete it */
495 RemoveEntryList(&(WorkItem
->UniqueIdWorkerItemListEntry
));
496 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
497 IoFreeIrp(WorkItem
->Irp
);
498 FreePool(WorkItem
->DeviceName
.Buffer
);
499 FreePool(WorkItem
->IrpBuffer
);
509 UniqueIdChangeNotifyWorker(IN PDEVICE_OBJECT DeviceObject
,
512 PUNIQUE_ID_WORK_ITEM WorkItem
= Context
;
513 PMOUNTDEV_UNIQUE_ID OldUniqueId
, NewUniqueId
;
514 PMOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT UniqueIdChange
;
516 UNREFERENCED_PARAMETER(DeviceObject
);
518 /* Validate worker */
519 if (!NT_SUCCESS(WorkItem
->Irp
->IoStatus
.Status
))
521 RemoveWorkItem(WorkItem
);
525 UniqueIdChange
= WorkItem
->Irp
->AssociatedIrp
.SystemBuffer
;
526 /* Get the old unique ID */
527 OldUniqueId
= AllocatePool(UniqueIdChange
->OldUniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
530 RemoveWorkItem(WorkItem
);
534 OldUniqueId
->UniqueIdLength
= UniqueIdChange
->OldUniqueIdLength
;
535 RtlCopyMemory(OldUniqueId
->UniqueId
,
536 (PVOID
)((ULONG_PTR
)UniqueIdChange
+ UniqueIdChange
->OldUniqueIdOffset
),
537 UniqueIdChange
->OldUniqueIdLength
);
539 /* Get the new unique ID */
540 NewUniqueId
= AllocatePool(UniqueIdChange
->NewUniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
543 FreePool(OldUniqueId
);
544 RemoveWorkItem(WorkItem
);
548 NewUniqueId
->UniqueIdLength
= UniqueIdChange
->NewUniqueIdLength
;
549 RtlCopyMemory(NewUniqueId
->UniqueId
,
550 (PVOID
)((ULONG_PTR
)UniqueIdChange
+ UniqueIdChange
->NewUniqueIdOffset
),
551 UniqueIdChange
->NewUniqueIdLength
);
553 /* Call the real worker */
554 MountMgrUniqueIdChangeRoutine(WorkItem
->DeviceExtension
, OldUniqueId
, NewUniqueId
);
555 IssueUniqueIdChangeNotifyWorker(WorkItem
, NewUniqueId
);
557 FreePool(NewUniqueId
);
558 FreePool(OldUniqueId
);
568 UniqueIdChangeNotifyCompletion(IN PDEVICE_OBJECT DeviceObject
,
572 PUNIQUE_ID_WORK_ITEM WorkItem
= Context
;
574 UNREFERENCED_PARAMETER(DeviceObject
);
575 UNREFERENCED_PARAMETER(Irp
);
577 /* Simply queue the work item */
578 IoQueueWorkItem(WorkItem
->WorkItem
,
579 UniqueIdChangeNotifyWorker
,
583 return STATUS_MORE_PROCESSING_REQUIRED
;
590 IssueUniqueIdChangeNotifyWorker(IN PUNIQUE_ID_WORK_ITEM WorkItem
,
591 IN PMOUNTDEV_UNIQUE_ID UniqueId
)
595 PFILE_OBJECT FileObject
;
596 PIO_STACK_LOCATION Stack
;
597 PDEVICE_OBJECT DeviceObject
;
599 /* Get the device object */
600 Status
= IoGetDeviceObjectPointer(&(WorkItem
->DeviceName
),
601 FILE_READ_ATTRIBUTES
,
604 if (!NT_SUCCESS(Status
))
606 RemoveWorkItem(WorkItem
);
610 /* And then, the attached device */
611 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
613 /* Initialize the IRP */
615 IoInitializeIrp(Irp
, IoSizeOfIrp(WorkItem
->StackSize
), (CCHAR
)WorkItem
->StackSize
);
617 if (InterlockedExchange((PLONG
)&(WorkItem
->Event
), 0) != 0)
619 ObDereferenceObject(FileObject
);
620 ObDereferenceObject(DeviceObject
);
621 RemoveWorkItem(WorkItem
);
625 Irp
->AssociatedIrp
.SystemBuffer
= WorkItem
->IrpBuffer
;
626 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
627 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, UniqueId
, UniqueId
->UniqueIdLength
+ sizeof(USHORT
));
629 Stack
= IoGetNextIrpStackLocation(Irp
);
631 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
= UniqueId
->UniqueIdLength
+ sizeof(USHORT
);
632 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
= WorkItem
->IrpBufferLength
;
633 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= 0;
634 Stack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY
;
635 Stack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
637 Status
= IoSetCompletionRoutineEx(WorkItem
->DeviceExtension
->DeviceObject
,
639 UniqueIdChangeNotifyCompletion
,
642 if (!NT_SUCCESS(Status
))
644 ObDereferenceObject(FileObject
);
645 ObDereferenceObject(DeviceObject
);
646 RemoveWorkItem(WorkItem
);
650 /* Call the driver */
651 IoCallDriver(DeviceObject
, Irp
);
652 ObDereferenceObject(FileObject
);
653 ObDereferenceObject(DeviceObject
);
660 IssueUniqueIdChangeNotify(IN PDEVICE_EXTENSION DeviceExtension
,
661 IN PUNICODE_STRING DeviceName
,
662 IN PMOUNTDEV_UNIQUE_ID UniqueId
)
665 PVOID IrpBuffer
= NULL
;
666 PFILE_OBJECT FileObject
;
667 PDEVICE_OBJECT DeviceObject
;
668 PUNIQUE_ID_WORK_ITEM WorkItem
= NULL
;
670 /* Get the associated device object */
671 Status
= IoGetDeviceObjectPointer(DeviceName
,
672 FILE_READ_ATTRIBUTES
,
675 if (!NT_SUCCESS(Status
))
680 /* And then, get attached device */
681 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
683 ObDereferenceObject(FileObject
);
685 /* Allocate a work item */
686 WorkItem
= AllocatePool(sizeof(UNIQUE_ID_WORK_ITEM
));
689 ObDereferenceObject(DeviceObject
);
693 WorkItem
->Event
= NULL
;
694 WorkItem
->WorkItem
= IoAllocateWorkItem(DeviceExtension
->DeviceObject
);
695 if (!WorkItem
->WorkItem
)
697 ObDereferenceObject(DeviceObject
);
701 WorkItem
->DeviceExtension
= DeviceExtension
;
702 WorkItem
->StackSize
= DeviceObject
->StackSize
;
703 /* Already provide the IRP */
704 WorkItem
->Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
706 ObDereferenceObject(DeviceObject
);
713 /* Ensure it has enough space */
714 IrpBuffer
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT
) + 1024);
720 WorkItem
->DeviceName
.Length
= DeviceName
->Length
;
721 WorkItem
->DeviceName
.MaximumLength
= DeviceName
->Length
+ sizeof(WCHAR
);
722 WorkItem
->DeviceName
.Buffer
= AllocatePool(WorkItem
->DeviceName
.MaximumLength
);
723 if (!WorkItem
->DeviceName
.Buffer
)
728 RtlCopyMemory(WorkItem
->DeviceName
.Buffer
, DeviceName
->Buffer
, DeviceName
->Length
);
729 WorkItem
->DeviceName
.Buffer
[DeviceName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
731 WorkItem
->IrpBuffer
= IrpBuffer
;
732 WorkItem
->IrpBufferLength
= sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT
) + 1024;
734 /* Add the worker in the list */
735 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
736 InsertHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
), &(WorkItem
->UniqueIdWorkerItemListEntry
));
737 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
739 /* And call the worker */
740 IssueUniqueIdChangeNotifyWorker(WorkItem
, UniqueId
);
752 IoFreeIrp(WorkItem
->Irp
);
755 if (WorkItem
->WorkItem
)
757 IoFreeWorkItem(WorkItem
->WorkItem
);