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 PTARGET_DEVICE_CUSTOM_NOTIFICATION Notification; 235 236 DeviceInformation = Context; 237 DeviceExtension = DeviceInformation->DeviceExtension; 238 Notification = NotificationStructure; 239 240 /* The notification have to be unregistered already (in device interface change handler) */ 241 ASSERT(!IsEqualGUID(&Notification->Event, &GUID_TARGET_DEVICE_REMOVE_COMPLETE)); 242 243 /* It it's to signal that a volume has been mounted 244 * Verify if a database sync is required and execute it 245 */ 246 if (IsEqualGUID(&(Notification->Event), &GUID_IO_VOLUME_MOUNT)) 247 { 248 /* If we were already mounted, then mark us unmounted */ 249 if (InterlockedCompareExchange(&(DeviceInformation->MountState), 250 FALSE, 251 FALSE) == TRUE) 252 { 253 InterlockedDecrement(&(DeviceInformation->MountState)); 254 } 255 /* Otherwise, start mounting the device and first, reconcile its DB if required */ 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 IoSetCancelRoutine(Irp, NULL); 330 InsertTailList(&CopyList, &(Irp->Tail.Overlay.ListEntry)); 331 } 332 IoReleaseCancelSpinLock(OldIrql); 333 334 /* Then, notify them one by one */ 335 while (!IsListEmpty(&CopyList)) 336 { 337 NextEntry = RemoveHeadList(&CopyList); 338 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); 339 340 *((PULONG)Irp->AssociatedIrp.SystemBuffer) = DeviceExtension->EpicNumber; 341 Irp->IoStatus.Information = sizeof(DeviceExtension->EpicNumber); 342 343 IoCompleteRequest(Irp, IO_NO_INCREMENT); 344 } 345 } 346 347 /* 348 * @implemented 349 */ 350 VOID 351 MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension, 352 IN PUNICODE_STRING DeviceName, 353 IN BOOLEAN ValidateVolume) 354 { 355 PIRP Irp; 356 KEVENT Event; 357 NTSTATUS Status; 358 PLIST_ENTRY NextEntry; 359 PFILE_OBJECT FileObject; 360 PIO_STACK_LOCATION Stack; 361 PDEVICE_OBJECT DeviceObject; 362 IO_STATUS_BLOCK IoStatusBlock; 363 PDEVICE_RELATIONS DeviceRelations; 364 PDEVICE_INFORMATION DeviceInformation; 365 TARGET_DEVICE_CUSTOM_NOTIFICATION DeviceNotification; 366 367 /* If we have to validate volume */ 368 if (ValidateVolume) 369 { 370 /* Then, ensure we can find the device */ 371 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 372 NextEntry != &DeviceExtension->DeviceListHead; 373 NextEntry = NextEntry->Flink) 374 { 375 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 376 if (RtlCompareUnicodeString(DeviceName, &(DeviceInformation->DeviceName), TRUE) == 0) 377 { 378 break; 379 } 380 } 381 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) 385 { 386 return; 387 } 388 } 389 390 /* Then, get device object */ 391 Status = IoGetDeviceObjectPointer(DeviceName, 392 FILE_READ_ATTRIBUTES, 393 &FileObject, 394 &DeviceObject); 395 if (!NT_SUCCESS(Status)) 396 { 397 return; 398 } 399 400 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 401 402 KeInitializeEvent(&Event, NotificationEvent, FALSE); 403 404 /* Set up empty IRP (yes, yes!) */ 405 Irp = IoBuildDeviceIoControlRequest(0, 406 DeviceObject, 407 NULL, 408 0, 409 NULL, 410 0, 411 FALSE, 412 &Event, 413 &IoStatusBlock); 414 if (!Irp) 415 { 416 ObDereferenceObject(DeviceObject); 417 ObDereferenceObject(FileObject); 418 return; 419 } 420 421 Stack = IoGetNextIrpStackLocation(Irp); 422 423 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 424 Irp->IoStatus.Information = 0; 425 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; 431 432 /* And call driver */ 433 Status = IoCallDriver(DeviceObject, Irp); 434 if (Status == STATUS_PENDING) 435 { 436 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 437 Status = IoStatusBlock.Status; 438 } 439 440 ObDereferenceObject(DeviceObject); 441 ObDereferenceObject(FileObject); 442 443 if (!NT_SUCCESS(Status)) 444 { 445 return; 446 } 447 448 /* Validate device return */ 449 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 450 if (DeviceRelations->Count < 1) 451 { 452 ExFreePool(DeviceRelations); 453 return; 454 } 455 456 DeviceObject = DeviceRelations->Objects[0]; 457 ExFreePool(DeviceRelations); 458 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; 465 466 /* And report */ 467 IoReportTargetDeviceChangeAsynchronous(DeviceObject, 468 &DeviceNotification, 469 NULL, NULL); 470 471 ObDereferenceObject(DeviceObject); 472 473 return; 474 } 475 476 /* 477 * @implemented 478 */ 479 VOID 480 RemoveWorkItem(IN PUNIQUE_ID_WORK_ITEM WorkItem) 481 { 482 PDEVICE_EXTENSION DeviceExtension = WorkItem->DeviceExtension; 483 484 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 485 486 /* If even if being worked, it's too late */ 487 if (WorkItem->Event) 488 { 489 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 490 KeSetEvent(WorkItem->Event, 0, FALSE); 491 } 492 else 493 { 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); 500 FreePool(WorkItem); 501 } 502 } 503 504 /* 505 * @implemented 506 */ 507 VOID 508 NTAPI 509 UniqueIdChangeNotifyWorker(IN PDEVICE_OBJECT DeviceObject, 510 IN PVOID Context) 511 { 512 PUNIQUE_ID_WORK_ITEM WorkItem = Context; 513 PMOUNTDEV_UNIQUE_ID OldUniqueId, NewUniqueId; 514 PMOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT UniqueIdChange; 515 516 UNREFERENCED_PARAMETER(DeviceObject); 517 518 /* Validate worker */ 519 if (!NT_SUCCESS(WorkItem->Irp->IoStatus.Status)) 520 { 521 RemoveWorkItem(WorkItem); 522 return; 523 } 524 525 UniqueIdChange = WorkItem->Irp->AssociatedIrp.SystemBuffer; 526 /* Get the old unique ID */ 527 OldUniqueId = AllocatePool(UniqueIdChange->OldUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 528 if (!OldUniqueId) 529 { 530 RemoveWorkItem(WorkItem); 531 return; 532 } 533 534 OldUniqueId->UniqueIdLength = UniqueIdChange->OldUniqueIdLength; 535 RtlCopyMemory(OldUniqueId->UniqueId, 536 (PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->OldUniqueIdOffset), 537 UniqueIdChange->OldUniqueIdLength); 538 539 /* Get the new unique ID */ 540 NewUniqueId = AllocatePool(UniqueIdChange->NewUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 541 if (!NewUniqueId) 542 { 543 FreePool(OldUniqueId); 544 RemoveWorkItem(WorkItem); 545 return; 546 } 547 548 NewUniqueId->UniqueIdLength = UniqueIdChange->NewUniqueIdLength; 549 RtlCopyMemory(NewUniqueId->UniqueId, 550 (PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->NewUniqueIdOffset), 551 UniqueIdChange->NewUniqueIdLength); 552 553 /* Call the real worker */ 554 MountMgrUniqueIdChangeRoutine(WorkItem->DeviceExtension, OldUniqueId, NewUniqueId); 555 IssueUniqueIdChangeNotifyWorker(WorkItem, NewUniqueId); 556 557 FreePool(NewUniqueId); 558 FreePool(OldUniqueId); 559 560 return; 561 } 562 563 /* 564 * @implemented 565 */ 566 NTSTATUS 567 NTAPI 568 UniqueIdChangeNotifyCompletion(IN PDEVICE_OBJECT DeviceObject, 569 IN PIRP Irp, 570 IN PVOID Context) 571 { 572 PUNIQUE_ID_WORK_ITEM WorkItem = Context; 573 574 UNREFERENCED_PARAMETER(DeviceObject); 575 UNREFERENCED_PARAMETER(Irp); 576 577 /* Simply queue the work item */ 578 IoQueueWorkItem(WorkItem->WorkItem, 579 UniqueIdChangeNotifyWorker, 580 DelayedWorkQueue, 581 WorkItem); 582 583 return STATUS_MORE_PROCESSING_REQUIRED; 584 } 585 586 /* 587 * @implemented 588 */ 589 VOID 590 IssueUniqueIdChangeNotifyWorker(IN PUNIQUE_ID_WORK_ITEM WorkItem, 591 IN PMOUNTDEV_UNIQUE_ID UniqueId) 592 { 593 PIRP Irp; 594 NTSTATUS Status; 595 PFILE_OBJECT FileObject; 596 PIO_STACK_LOCATION Stack; 597 PDEVICE_OBJECT DeviceObject; 598 599 /* Get the device object */ 600 Status = IoGetDeviceObjectPointer(&(WorkItem->DeviceName), 601 FILE_READ_ATTRIBUTES, 602 &FileObject, 603 &DeviceObject); 604 if (!NT_SUCCESS(Status)) 605 { 606 RemoveWorkItem(WorkItem); 607 return; 608 } 609 610 /* And then, the attached device */ 611 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 612 613 /* Initialize the IRP */ 614 Irp = WorkItem->Irp; 615 IoInitializeIrp(Irp, IoSizeOfIrp(WorkItem->StackSize), (CCHAR)WorkItem->StackSize); 616 617 if (InterlockedExchange((PLONG)&(WorkItem->Event), 0) != 0) 618 { 619 ObDereferenceObject(FileObject); 620 ObDereferenceObject(DeviceObject); 621 RemoveWorkItem(WorkItem); 622 return; 623 } 624 625 Irp->AssociatedIrp.SystemBuffer = WorkItem->IrpBuffer; 626 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 627 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, UniqueId, UniqueId->UniqueIdLength + sizeof(USHORT)); 628 629 Stack = IoGetNextIrpStackLocation(Irp); 630 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; 636 637 Status = IoSetCompletionRoutineEx(WorkItem->DeviceExtension->DeviceObject, 638 Irp, 639 UniqueIdChangeNotifyCompletion, 640 WorkItem, 641 TRUE, TRUE, TRUE); 642 if (!NT_SUCCESS(Status)) 643 { 644 ObDereferenceObject(FileObject); 645 ObDereferenceObject(DeviceObject); 646 RemoveWorkItem(WorkItem); 647 return; 648 } 649 650 /* Call the driver */ 651 IoCallDriver(DeviceObject, Irp); 652 ObDereferenceObject(FileObject); 653 ObDereferenceObject(DeviceObject); 654 } 655 656 /* 657 * @implemented 658 */ 659 VOID 660 IssueUniqueIdChangeNotify(IN PDEVICE_EXTENSION DeviceExtension, 661 IN PUNICODE_STRING DeviceName, 662 IN PMOUNTDEV_UNIQUE_ID UniqueId) 663 { 664 NTSTATUS Status; 665 PVOID IrpBuffer = NULL; 666 PFILE_OBJECT FileObject; 667 PDEVICE_OBJECT DeviceObject; 668 PUNIQUE_ID_WORK_ITEM WorkItem = NULL; 669 670 /* Get the associated device object */ 671 Status = IoGetDeviceObjectPointer(DeviceName, 672 FILE_READ_ATTRIBUTES, 673 &FileObject, 674 &DeviceObject); 675 if (!NT_SUCCESS(Status)) 676 { 677 return; 678 } 679 680 /* And then, get attached device */ 681 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 682 683 ObDereferenceObject(FileObject); 684 685 /* Allocate a work item */ 686 WorkItem = AllocatePool(sizeof(UNIQUE_ID_WORK_ITEM)); 687 if (!WorkItem) 688 { 689 ObDereferenceObject(DeviceObject); 690 return; 691 } 692 693 WorkItem->Event = NULL; 694 WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject); 695 if (!WorkItem->WorkItem) 696 { 697 ObDereferenceObject(DeviceObject); 698 goto Cleanup; 699 } 700 701 WorkItem->DeviceExtension = DeviceExtension; 702 WorkItem->StackSize = DeviceObject->StackSize; 703 /* Already provide the IRP */ 704 WorkItem->Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 705 706 ObDereferenceObject(DeviceObject); 707 708 if (!WorkItem->Irp) 709 { 710 goto Cleanup; 711 } 712 713 /* Ensure it has enough space */ 714 IrpBuffer = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024); 715 if (!IrpBuffer) 716 { 717 goto Cleanup; 718 } 719 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) 724 { 725 goto Cleanup; 726 } 727 728 RtlCopyMemory(WorkItem->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length); 729 WorkItem->DeviceName.Buffer[DeviceName->Length / sizeof(WCHAR)] = UNICODE_NULL; 730 731 WorkItem->IrpBuffer = IrpBuffer; 732 WorkItem->IrpBufferLength = sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024; 733 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); 738 739 /* And call the worker */ 740 IssueUniqueIdChangeNotifyWorker(WorkItem, UniqueId); 741 742 return; 743 744 Cleanup: 745 if (IrpBuffer) 746 { 747 FreePool(IrpBuffer); 748 } 749 750 if (WorkItem->Irp) 751 { 752 IoFreeIrp(WorkItem->Irp); 753 } 754 755 if (WorkItem->WorkItem) 756 { 757 IoFreeWorkItem(WorkItem->WorkItem); 758 } 759 760 if (WorkItem) 761 { 762 FreePool(WorkItem); 763 } 764 } 765