[USBPORT] Add USB2_InitTT().
[reactos.git] / drivers / filters / mountmgr / notify.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2011 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 *
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)
25 */
26
27 #include "mntmgr.h"
28
29 #include <ioevent.h>
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /*
35 * @implemented
36 */
37 VOID
38 SendOnlineNotification(IN PUNICODE_STRING SymbolicName)
39 {
40 PIRP Irp;
41 KEVENT Event;
42 NTSTATUS Status;
43 PFILE_OBJECT FileObject;
44 PIO_STACK_LOCATION Stack;
45 PDEVICE_OBJECT DeviceObject;
46 IO_STATUS_BLOCK IoStatusBlock;
47
48 /* Get device object */
49 Status = IoGetDeviceObjectPointer(SymbolicName,
50 FILE_READ_ATTRIBUTES,
51 &FileObject,
52 &DeviceObject);
53 if (!NT_SUCCESS(Status))
54 {
55 return;
56 }
57
58 /* And attached device object */
59 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
60
61 /* And send VOLUME_ONLINE */
62 KeInitializeEvent(&Event, NotificationEvent, FALSE);
63 Irp = IoBuildDeviceIoControlRequest(IOCTL_VOLUME_ONLINE,
64 DeviceObject,
65 NULL, 0,
66 NULL, 0,
67 FALSE,
68 &Event,
69 &IoStatusBlock);
70 if (!Irp)
71 {
72 goto Cleanup;
73 }
74
75 Stack = IoGetNextIrpStackLocation(Irp);
76 Stack->FileObject = FileObject;
77
78 Status = IoCallDriver(DeviceObject, Irp);
79 if (Status == STATUS_PENDING)
80 {
81 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
82 }
83
84 Cleanup:
85 ObDereferenceObject(DeviceObject);
86 ObDereferenceObject(FileObject);
87
88 return;
89 }
90
91 /*
92 * @implemented
93 */
94 VOID
95 NTAPI
96 SendOnlineNotificationWorker(IN PVOID Parameter)
97 {
98 KIRQL OldIrql;
99 PLIST_ENTRY Head;
100 PDEVICE_EXTENSION DeviceExtension;
101 PONLINE_NOTIFICATION_WORK_ITEM WorkItem;
102 PONLINE_NOTIFICATION_WORK_ITEM NewWorkItem;
103
104 WorkItem = (PONLINE_NOTIFICATION_WORK_ITEM)Parameter;
105 DeviceExtension = WorkItem->DeviceExtension;
106
107 /* First, send the notification */
108 SendOnlineNotification(&(WorkItem->SymbolicName));
109
110 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
111 /* If there are no notifications running any longer, reset event */
112 if (--DeviceExtension->OnlineNotificationCount == 0)
113 {
114 KeSetEvent(&(DeviceExtension->OnlineNotificationEvent), 0, FALSE);
115 }
116
117 /* If there are still notifications in queue */
118 if (!IsListEmpty(&(DeviceExtension->OnlineNotificationListHead)))
119 {
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);
127 }
128 else
129 {
130 /* Mark it's over */
131 DeviceExtension->OnlineNotificationWorkerActive = 0;
132 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
133 }
134
135 FreePool(WorkItem->SymbolicName.Buffer);
136 FreePool(WorkItem);
137
138 return;
139 }
140
141 /*
142 * @implemented
143 */
144 VOID
145 PostOnlineNotification(IN PDEVICE_EXTENSION DeviceExtension,
146 IN PUNICODE_STRING SymbolicName)
147 {
148 KIRQL OldIrql;
149 PONLINE_NOTIFICATION_WORK_ITEM WorkItem;
150
151 /* Allocate a notification work item */
152 WorkItem = AllocatePool(sizeof(ONLINE_NOTIFICATION_WORK_ITEM));
153 if (!WorkItem)
154 {
155 return;
156 }
157
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)
164 {
165 FreePool(WorkItem);
166 return;
167 }
168
169 RtlCopyMemory(WorkItem->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length);
170 WorkItem->SymbolicName.Buffer[SymbolicName->Length / sizeof(WCHAR)] = UNICODE_NULL;
171
172 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
173 DeviceExtension->OnlineNotificationCount++;
174
175 /* If no worker are active */
176 if (DeviceExtension->OnlineNotificationWorkerActive == 0)
177 {
178 /* Queue that one for execution */
179 DeviceExtension->OnlineNotificationWorkerActive = 1;
180 ExQueueWorkItem(&WorkItem->WorkItem, DelayedWorkQueue);
181 }
182 else
183 {
184 /* Otherwise, just put it in the queue list */
185 InsertTailList(&(DeviceExtension->OnlineNotificationListHead), &(WorkItem->WorkItem.List));
186 }
187
188 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
189
190 return;
191 }
192
193 /*
194 * @implemented
195 */
196 VOID
197 WaitForOnlinesToComplete(IN PDEVICE_EXTENSION DeviceExtension)
198 {
199 KIRQL OldIrql;
200
201 KeInitializeEvent(&(DeviceExtension->OnlineNotificationEvent), NotificationEvent, FALSE);
202
203 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
204
205 /* Just wait all the worker are done */
206 if (DeviceExtension->OnlineNotificationCount != 1)
207 {
208 DeviceExtension->OnlineNotificationCount--;
209 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
210
211 KeWaitForSingleObject(&(DeviceExtension->OnlineNotificationEvent),
212 Executive,
213 KernelMode,
214 FALSE,
215 NULL);
216
217 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
218 DeviceExtension->OnlineNotificationCount++;
219 }
220
221 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
222 }
223
224 /*
225 * @implemented
226 */
227 NTSTATUS
228 NTAPI
229 MountMgrTargetDeviceNotification(IN PVOID NotificationStructure,
230 IN PVOID Context)
231 {
232 PDEVICE_EXTENSION DeviceExtension;
233 PDEVICE_INFORMATION DeviceInformation;
234 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification;
235
236 DeviceInformation = Context;
237 DeviceExtension = DeviceInformation->DeviceExtension;
238 Notification = NotificationStructure;
239
240 /* If it's to signal that removal is complete, then, execute the function */
241 if (IsEqualGUID(&(Notification->Event), &GUID_TARGET_DEVICE_REMOVE_COMPLETE))
242 {
243 MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName);
244 }
245 /* It it's to signal that a volume has been mounted
246 * Verify if a database sync is required and execute it
247 */
248 else if (IsEqualGUID(&(Notification->Event), &GUID_IO_VOLUME_MOUNT))
249 {
250 if (InterlockedCompareExchange(&(DeviceInformation->MountState),
251 FALSE,
252 TRUE) == TRUE)
253 {
254 InterlockedDecrement(&(DeviceInformation->MountState));
255 }
256 else
257 {
258 if (DeviceInformation->NeedsReconcile)
259 {
260 DeviceInformation->NeedsReconcile = FALSE;
261 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
262 }
263 }
264 }
265
266 return STATUS_SUCCESS;
267 }
268
269 /*
270 * @implemented
271 */
272 VOID
273 RegisterForTargetDeviceNotification(IN PDEVICE_EXTENSION DeviceExtension,
274 IN PDEVICE_INFORMATION DeviceInformation)
275 {
276 NTSTATUS Status;
277 PFILE_OBJECT FileObject;
278 PDEVICE_OBJECT DeviceObject;
279
280 /* Get device object */
281 Status = IoGetDeviceObjectPointer(&(DeviceInformation->DeviceName),
282 FILE_READ_ATTRIBUTES,
283 &FileObject,
284 &DeviceObject);
285 if (!NT_SUCCESS(Status))
286 {
287 return;
288 }
289
290 /* And simply register for notifications */
291 Status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange,
292 0, FileObject,
293 DeviceExtension->DriverObject,
294 MountMgrTargetDeviceNotification,
295 DeviceInformation,
296 &(DeviceInformation->TargetDeviceNotificationEntry));
297 if (!NT_SUCCESS(Status))
298 {
299 DeviceInformation->TargetDeviceNotificationEntry = NULL;
300 }
301
302 ObDereferenceObject(FileObject);
303
304 return;
305 }
306
307 /*
308 * @implemented
309 */
310 VOID
311 MountMgrNotify(IN PDEVICE_EXTENSION DeviceExtension)
312 {
313 PIRP Irp;
314 KIRQL OldIrql;
315 LIST_ENTRY CopyList;
316 PLIST_ENTRY NextEntry;
317
318 /* Increase the epic number */
319 DeviceExtension->EpicNumber++;
320
321 InitializeListHead(&CopyList);
322
323 /* Copy all the pending IRPs for notification */
324 IoAcquireCancelSpinLock(&OldIrql);
325 while (!IsListEmpty(&(DeviceExtension->IrpListHead)))
326 {
327 NextEntry = RemoveHeadList(&(DeviceExtension->IrpListHead));
328 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
329 InsertTailList(&CopyList, &(Irp->Tail.Overlay.ListEntry));
330 }
331 IoReleaseCancelSpinLock(OldIrql);
332
333 /* Then, notify them one by one */
334 while (!IsListEmpty(&CopyList))
335 {
336 NextEntry = RemoveHeadList(&CopyList);
337 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
338
339 *((PULONG)Irp->AssociatedIrp.SystemBuffer) = DeviceExtension->EpicNumber;
340 Irp->IoStatus.Information = sizeof(DeviceExtension->EpicNumber);
341
342 IoCompleteRequest(Irp, IO_NO_INCREMENT);
343 }
344 }
345
346 /*
347 * @implemented
348 */
349 VOID
350 MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension,
351 IN PUNICODE_STRING DeviceName,
352 IN BOOLEAN ValidateVolume)
353 {
354 PIRP Irp;
355 KEVENT Event;
356 NTSTATUS Status;
357 PLIST_ENTRY NextEntry;
358 PFILE_OBJECT FileObject;
359 PIO_STACK_LOCATION Stack;
360 PDEVICE_OBJECT DeviceObject;
361 IO_STATUS_BLOCK IoStatusBlock;
362 PDEVICE_RELATIONS DeviceRelations;
363 PDEVICE_INFORMATION DeviceInformation;
364 TARGET_DEVICE_CUSTOM_NOTIFICATION DeviceNotification;
365
366 /* If we have to validate volume */
367 if (ValidateVolume)
368 {
369 /* Then, ensure we can find the device */
370 NextEntry = DeviceExtension->DeviceListHead.Flink;
371 while (NextEntry != &(DeviceExtension->DeviceListHead))
372 {
373 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
374 if (RtlCompareUnicodeString(DeviceName, &(DeviceInformation->DeviceName), TRUE) == 0)
375 {
376 break;
377 }
378 }
379
380 /* No need to notify for a PnP device or if we didn't find the device */
381 if (NextEntry == &(DeviceExtension->DeviceListHead) ||
382 !DeviceInformation->ManuallyRegistered)
383 {
384 return;
385 }
386 }
387
388 /* Then, get device object */
389 Status = IoGetDeviceObjectPointer(DeviceName,
390 FILE_READ_ATTRIBUTES,
391 &FileObject,
392 &DeviceObject);
393 if (!NT_SUCCESS(Status))
394 {
395 return;
396 }
397
398 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
399
400 KeInitializeEvent(&Event, NotificationEvent, FALSE);
401
402 /* Set up empty IRP (yes, yes!) */
403 Irp = IoBuildDeviceIoControlRequest(0,
404 DeviceObject,
405 NULL,
406 0,
407 NULL,
408 0,
409 FALSE,
410 &Event,
411 &IoStatusBlock);
412 if (!Irp)
413 {
414 ObDereferenceObject(DeviceObject);
415 ObDereferenceObject(FileObject);
416 return;
417 }
418
419 Stack = IoGetNextIrpStackLocation(Irp);
420
421 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
422 Irp->IoStatus.Information = 0;
423
424 /* Properly set it, we want to query device relations */
425 Stack->MajorFunction = IRP_MJ_PNP;
426 Stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
427 Stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
428 Stack->FileObject = FileObject;
429
430 /* And call driver */
431 Status = IoCallDriver(DeviceObject, Irp);
432 if (Status == STATUS_PENDING)
433 {
434 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
435 Status = IoStatusBlock.Status;
436 }
437
438 ObDereferenceObject(DeviceObject);
439 ObDereferenceObject(FileObject);
440
441 if (!NT_SUCCESS(Status))
442 {
443 return;
444 }
445
446 /* Validate device return */
447 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
448 if (DeviceRelations->Count < 1)
449 {
450 ExFreePool(DeviceRelations);
451 return;
452 }
453
454 DeviceObject = DeviceRelations->Objects[0];
455 ExFreePool(DeviceRelations);
456
457 /* Set up real notification */
458 DeviceNotification.Version = 1;
459 DeviceNotification.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
460 DeviceNotification.Event = GUID_IO_VOLUME_NAME_CHANGE;
461 DeviceNotification.FileObject = NULL;
462 DeviceNotification.NameBufferOffset = -1;
463
464 /* And report */
465 IoReportTargetDeviceChangeAsynchronous(DeviceObject,
466 &DeviceNotification,
467 NULL, NULL);
468
469 ObDereferenceObject(DeviceObject);
470
471 return;
472 }
473
474 /*
475 * @implemented
476 */
477 VOID
478 RemoveWorkItem(IN PUNIQUE_ID_WORK_ITEM WorkItem)
479 {
480 PDEVICE_EXTENSION DeviceExtension = WorkItem->DeviceExtension;
481
482 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
483
484 /* If even if being worked, it's too late */
485 if (WorkItem->Event)
486 {
487 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
488 KeSetEvent(WorkItem->Event, 0, FALSE);
489 }
490 else
491 {
492 /* Otherwise, remove it from the list, and delete it */
493 RemoveEntryList(&(WorkItem->UniqueIdWorkerItemListEntry));
494 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
495 IoFreeIrp(WorkItem->Irp);
496 FreePool(WorkItem->DeviceName.Buffer);
497 FreePool(WorkItem->IrpBuffer);
498 FreePool(WorkItem);
499 }
500 }
501
502 /*
503 * @implemented
504 */
505 VOID
506 NTAPI
507 UniqueIdChangeNotifyWorker(IN PDEVICE_OBJECT DeviceObject,
508 IN PVOID Context)
509 {
510 PUNIQUE_ID_WORK_ITEM WorkItem = Context;
511 PMOUNTDEV_UNIQUE_ID OldUniqueId, NewUniqueId;
512 PMOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT UniqueIdChange;
513
514 UNREFERENCED_PARAMETER(DeviceObject);
515
516 /* Validate worker */
517 if (!NT_SUCCESS(WorkItem->Irp->IoStatus.Status))
518 {
519 RemoveWorkItem(WorkItem);
520 return;
521 }
522
523 UniqueIdChange = WorkItem->Irp->AssociatedIrp.SystemBuffer;
524 /* Get the old unique ID */
525 OldUniqueId = AllocatePool(UniqueIdChange->OldUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
526 if (!OldUniqueId)
527 {
528 RemoveWorkItem(WorkItem);
529 return;
530 }
531
532 OldUniqueId->UniqueIdLength = UniqueIdChange->OldUniqueIdLength;
533 RtlCopyMemory(OldUniqueId->UniqueId,
534 (PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->OldUniqueIdOffset),
535 UniqueIdChange->OldUniqueIdLength);
536
537 /* Get the new unique ID */
538 NewUniqueId = AllocatePool(UniqueIdChange->NewUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
539 if (!NewUniqueId)
540 {
541 FreePool(OldUniqueId);
542 RemoveWorkItem(WorkItem);
543 return;
544 }
545
546 NewUniqueId->UniqueIdLength = UniqueIdChange->NewUniqueIdLength;
547 RtlCopyMemory(NewUniqueId->UniqueId,
548 (PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->NewUniqueIdOffset),
549 UniqueIdChange->NewUniqueIdLength);
550
551 /* Call the real worker */
552 MountMgrUniqueIdChangeRoutine(WorkItem->DeviceExtension, OldUniqueId, NewUniqueId);
553 IssueUniqueIdChangeNotifyWorker(WorkItem, NewUniqueId);
554
555 FreePool(NewUniqueId);
556 FreePool(OldUniqueId);
557
558 return;
559 }
560
561 /*
562 * @implemented
563 */
564 NTSTATUS
565 NTAPI
566 UniqueIdChangeNotifyCompletion(IN PDEVICE_OBJECT DeviceObject,
567 IN PIRP Irp,
568 IN PVOID Context)
569 {
570 PUNIQUE_ID_WORK_ITEM WorkItem = Context;
571
572 UNREFERENCED_PARAMETER(DeviceObject);
573 UNREFERENCED_PARAMETER(Irp);
574
575 /* Simply queue the work item */
576 IoQueueWorkItem(WorkItem->WorkItem,
577 UniqueIdChangeNotifyWorker,
578 DelayedWorkQueue,
579 WorkItem);
580
581 return STATUS_MORE_PROCESSING_REQUIRED;
582 }
583
584 /*
585 * @implemented
586 */
587 VOID
588 IssueUniqueIdChangeNotifyWorker(IN PUNIQUE_ID_WORK_ITEM WorkItem,
589 IN PMOUNTDEV_UNIQUE_ID UniqueId)
590 {
591 PIRP Irp;
592 NTSTATUS Status;
593 PFILE_OBJECT FileObject;
594 PIO_STACK_LOCATION Stack;
595 PDEVICE_OBJECT DeviceObject;
596
597 /* Get the device object */
598 Status = IoGetDeviceObjectPointer(&(WorkItem->DeviceName),
599 FILE_READ_ATTRIBUTES,
600 &FileObject,
601 &DeviceObject);
602 if (!NT_SUCCESS(Status))
603 {
604 RemoveWorkItem(WorkItem);
605 return;
606 }
607
608 /* And then, the attached device */
609 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
610
611 /* Initialize the IRP */
612 Irp = WorkItem->Irp;
613 IoInitializeIrp(Irp, IoSizeOfIrp(WorkItem->StackSize), (CCHAR)WorkItem->StackSize);
614
615 if (InterlockedExchange((PLONG)&(WorkItem->Event), 0) != 0)
616 {
617 ObDereferenceObject(FileObject);
618 ObDereferenceObject(DeviceObject);
619 RemoveWorkItem(WorkItem);
620 return;
621 }
622
623 Irp->AssociatedIrp.SystemBuffer = WorkItem->IrpBuffer;
624 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
625 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, UniqueId, UniqueId->UniqueIdLength + sizeof(USHORT));
626
627 Stack = IoGetNextIrpStackLocation(Irp);
628
629 Stack->Parameters.DeviceIoControl.InputBufferLength = UniqueId->UniqueIdLength + sizeof(USHORT);
630 Stack->Parameters.DeviceIoControl.OutputBufferLength = WorkItem->IrpBufferLength;
631 Stack->Parameters.DeviceIoControl.Type3InputBuffer = 0;
632 Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY;
633 Stack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
634
635 Status = IoSetCompletionRoutineEx(WorkItem->DeviceExtension->DeviceObject,
636 Irp,
637 UniqueIdChangeNotifyCompletion,
638 WorkItem,
639 TRUE, TRUE, TRUE);
640 if (!NT_SUCCESS(Status))
641 {
642 ObDereferenceObject(FileObject);
643 ObDereferenceObject(DeviceObject);
644 RemoveWorkItem(WorkItem);
645 return;
646 }
647
648 /* Call the driver */
649 IoCallDriver(DeviceObject, Irp);
650 ObDereferenceObject(FileObject);
651 ObDereferenceObject(DeviceObject);
652 }
653
654 /*
655 * @implemented
656 */
657 VOID
658 IssueUniqueIdChangeNotify(IN PDEVICE_EXTENSION DeviceExtension,
659 IN PUNICODE_STRING DeviceName,
660 IN PMOUNTDEV_UNIQUE_ID UniqueId)
661 {
662 NTSTATUS Status;
663 PVOID IrpBuffer = NULL;
664 PFILE_OBJECT FileObject;
665 PDEVICE_OBJECT DeviceObject;
666 PUNIQUE_ID_WORK_ITEM WorkItem = NULL;
667
668 /* Get the associated device object */
669 Status = IoGetDeviceObjectPointer(DeviceName,
670 FILE_READ_ATTRIBUTES,
671 &FileObject,
672 &DeviceObject);
673 if (!NT_SUCCESS(Status))
674 {
675 return;
676 }
677
678 /* And then, get attached device */
679 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
680
681 ObDereferenceObject(FileObject);
682
683 /* Allocate a work item */
684 WorkItem = AllocatePool(sizeof(UNIQUE_ID_WORK_ITEM));
685 if (!WorkItem)
686 {
687 ObDereferenceObject(DeviceObject);
688 return;
689 }
690
691 WorkItem->Event = NULL;
692 WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject);
693 if (!WorkItem->WorkItem)
694 {
695 ObDereferenceObject(DeviceObject);
696 goto Cleanup;
697 }
698
699 WorkItem->DeviceExtension = DeviceExtension;
700 WorkItem->StackSize = DeviceObject->StackSize;
701 /* Already provide the IRP */
702 WorkItem->Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
703
704 ObDereferenceObject(DeviceObject);
705
706 if (!WorkItem->Irp)
707 {
708 goto Cleanup;
709 }
710
711 /* Ensure it has enough space */
712 IrpBuffer = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024);
713 if (!IrpBuffer)
714 {
715 goto Cleanup;
716 }
717
718 WorkItem->DeviceName.Length = DeviceName->Length;
719 WorkItem->DeviceName.MaximumLength = DeviceName->Length + sizeof(WCHAR);
720 WorkItem->DeviceName.Buffer = AllocatePool(WorkItem->DeviceName.MaximumLength);
721 if (!WorkItem->DeviceName.Buffer)
722 {
723 goto Cleanup;
724 }
725
726 RtlCopyMemory(WorkItem->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length);
727 WorkItem->DeviceName.Buffer[DeviceName->Length / sizeof(WCHAR)] = UNICODE_NULL;
728
729 WorkItem->IrpBuffer = IrpBuffer;
730 WorkItem->IrpBufferLength = sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024;
731
732 /* Add the worker in the list */
733 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
734 InsertHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead), &(WorkItem->UniqueIdWorkerItemListEntry));
735 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
736
737 /* And call the worker */
738 IssueUniqueIdChangeNotifyWorker(WorkItem, UniqueId);
739
740 return;
741
742 Cleanup:
743 if (IrpBuffer)
744 {
745 FreePool(IrpBuffer);
746 }
747
748 if (WorkItem->Irp)
749 {
750 IoFreeIrp(WorkItem->Irp);
751 }
752
753 if (WorkItem->WorkItem)
754 {
755 IoFreeWorkItem(WorkItem->WorkItem);
756 }
757
758 if (WorkItem)
759 {
760 FreePool(WorkItem);
761 }
762 }