1 /* 2 * PROJECT: VFAT Filesystem 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Misc routines 5 * COPYRIGHT: Copyright 1998 Jason Filby <jasonfilby@yahoo.com> 6 * Copyright 2015-2018 Pierre Schweitzer <pierre@reactos.org> 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include "vfat.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS ******************************************************************/ 17 18 const char* MajorFunctionNames[] = 19 { 20 "IRP_MJ_CREATE", 21 "IRP_MJ_CREATE_NAMED_PIPE", 22 "IRP_MJ_CLOSE", 23 "IRP_MJ_READ", 24 "IRP_MJ_WRITE", 25 "IRP_MJ_QUERY_INFORMATION", 26 "IRP_MJ_SET_INFORMATION", 27 "IRP_MJ_QUERY_EA", 28 "IRP_MJ_SET_EA", 29 "IRP_MJ_FLUSH_BUFFERS", 30 "IRP_MJ_QUERY_VOLUME_INFORMATION", 31 "IRP_MJ_SET_VOLUME_INFORMATION", 32 "IRP_MJ_DIRECTORY_CONTROL", 33 "IRP_MJ_FILE_SYSTEM_CONTROL", 34 "IRP_MJ_DEVICE_CONTROL", 35 "IRP_MJ_INTERNAL_DEVICE_CONTROL", 36 "IRP_MJ_SHUTDOWN", 37 "IRP_MJ_LOCK_CONTROL", 38 "IRP_MJ_CLEANUP", 39 "IRP_MJ_CREATE_MAILSLOT", 40 "IRP_MJ_QUERY_SECURITY", 41 "IRP_MJ_SET_SECURITY", 42 "IRP_MJ_POWER", 43 "IRP_MJ_SYSTEM_CONTROL", 44 "IRP_MJ_DEVICE_CHANGE", 45 "IRP_MJ_QUERY_QUOTA", 46 "IRP_MJ_SET_QUOTA", 47 "IRP_MJ_PNP", 48 "IRP_MJ_MAXIMUM_FUNCTION" 49 }; 50 51 static LONG QueueCount = 0; 52 53 static VOID VfatFreeIrpContext(PVFAT_IRP_CONTEXT); 54 static PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT, PIRP); 55 static NTSTATUS VfatQueueRequest(PVFAT_IRP_CONTEXT); 56 57 /* FUNCTIONS ****************************************************************/ 58 59 static 60 NTSTATUS 61 VfatLockControl( 62 IN PVFAT_IRP_CONTEXT IrpContext) 63 { 64 PVFATFCB Fcb; 65 NTSTATUS Status; 66 67 DPRINT("VfatLockControl(IrpContext %p)\n", IrpContext); 68 69 ASSERT(IrpContext); 70 71 Fcb = (PVFATFCB)IrpContext->FileObject->FsContext; 72 73 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) 74 { 75 return STATUS_INVALID_DEVICE_REQUEST; 76 } 77 78 if (vfatFCBIsDirectory(Fcb)) 79 { 80 return STATUS_INVALID_PARAMETER; 81 } 82 83 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE; 84 Status = FsRtlProcessFileLock(&Fcb->FileLock, 85 IrpContext->Irp, 86 NULL); 87 return Status; 88 } 89 90 static 91 NTSTATUS 92 VfatDeviceControl( 93 IN PVFAT_IRP_CONTEXT IrpContext) 94 { 95 IoSkipCurrentIrpStackLocation(IrpContext->Irp); 96 97 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE; 98 99 return IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); 100 } 101 102 static 103 NTSTATUS 104 VfatDispatchRequest( 105 IN PVFAT_IRP_CONTEXT IrpContext) 106 { 107 NTSTATUS Status; 108 BOOLEAN QueueIrp, CompleteIrp; 109 110 DPRINT("VfatDispatchRequest (IrpContext %p), is called for %s\n", IrpContext, 111 IrpContext->MajorFunction >= IRP_MJ_MAXIMUM_FUNCTION ? "????" : MajorFunctionNames[IrpContext->MajorFunction]); 112 113 ASSERT(IrpContext); 114 115 FsRtlEnterFileSystem(); 116 117 switch (IrpContext->MajorFunction) 118 { 119 case IRP_MJ_CLOSE: 120 Status = VfatClose(IrpContext); 121 break; 122 123 case IRP_MJ_CREATE: 124 Status = VfatCreate(IrpContext); 125 break; 126 127 case IRP_MJ_READ: 128 Status = VfatRead(IrpContext); 129 break; 130 131 case IRP_MJ_WRITE: 132 Status = VfatWrite(&IrpContext); 133 break; 134 135 case IRP_MJ_FILE_SYSTEM_CONTROL: 136 Status = VfatFileSystemControl(IrpContext); 137 break; 138 139 case IRP_MJ_QUERY_INFORMATION: 140 Status = VfatQueryInformation(IrpContext); 141 break; 142 143 case IRP_MJ_SET_INFORMATION: 144 Status = VfatSetInformation(IrpContext); 145 break; 146 147 case IRP_MJ_DIRECTORY_CONTROL: 148 Status = VfatDirectoryControl(IrpContext); 149 break; 150 151 case IRP_MJ_QUERY_VOLUME_INFORMATION: 152 Status = VfatQueryVolumeInformation(IrpContext); 153 break; 154 155 case IRP_MJ_SET_VOLUME_INFORMATION: 156 Status = VfatSetVolumeInformation(IrpContext); 157 break; 158 159 case IRP_MJ_LOCK_CONTROL: 160 Status = VfatLockControl(IrpContext); 161 break; 162 163 case IRP_MJ_DEVICE_CONTROL: 164 Status = VfatDeviceControl(IrpContext); 165 break; 166 167 case IRP_MJ_CLEANUP: 168 Status = VfatCleanup(IrpContext); 169 break; 170 171 case IRP_MJ_FLUSH_BUFFERS: 172 Status = VfatFlush(IrpContext); 173 break; 174 175 case IRP_MJ_PNP: 176 Status = VfatPnp(IrpContext); 177 break; 178 179 default: 180 DPRINT1("Unexpected major function %x\n", IrpContext->MajorFunction); 181 Status = STATUS_DRIVER_INTERNAL_ERROR; 182 } 183 184 if (IrpContext != NULL) 185 { 186 QueueIrp = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_QUEUE); 187 CompleteIrp = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_COMPLETE); 188 189 ASSERT((!CompleteIrp && !QueueIrp) || 190 (CompleteIrp && !QueueIrp) || 191 (!CompleteIrp && QueueIrp)); 192 193 if (CompleteIrp) 194 { 195 IrpContext->Irp->IoStatus.Status = Status; 196 IoCompleteRequest(IrpContext->Irp, IrpContext->PriorityBoost); 197 } 198 199 if (QueueIrp) 200 { 201 /* Reset our status flags before queueing the IRP */ 202 IrpContext->Flags |= IRPCONTEXT_COMPLETE; 203 IrpContext->Flags &= ~IRPCONTEXT_QUEUE; 204 Status = VfatQueueRequest(IrpContext); 205 } 206 else 207 { 208 /* Unless the IRP was queued, always free the IRP context */ 209 VfatFreeIrpContext(IrpContext); 210 } 211 } 212 213 FsRtlExitFileSystem(); 214 215 return Status; 216 } 217 218 VOID 219 NTAPI 220 VfatHandleDeferredWrite( 221 IN PVOID IrpContext, 222 IN PVOID Unused) 223 { 224 VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext); 225 } 226 227 NTSTATUS 228 NTAPI 229 VfatBuildRequest( 230 IN PDEVICE_OBJECT DeviceObject, 231 IN PIRP Irp) 232 { 233 NTSTATUS Status; 234 PVFAT_IRP_CONTEXT IrpContext; 235 236 DPRINT("VfatBuildRequest (DeviceObject %p, Irp %p)\n", DeviceObject, Irp); 237 238 ASSERT(DeviceObject); 239 ASSERT(Irp); 240 241 IrpContext = VfatAllocateIrpContext(DeviceObject, Irp); 242 if (IrpContext == NULL) 243 { 244 Status = STATUS_INSUFFICIENT_RESOURCES; 245 Irp->IoStatus.Status = Status; 246 IoCompleteRequest(Irp, IO_NO_INCREMENT); 247 } 248 else 249 { 250 Status = VfatDispatchRequest(IrpContext); 251 } 252 return Status; 253 } 254 255 static 256 VOID 257 VfatFreeIrpContext( 258 PVFAT_IRP_CONTEXT IrpContext) 259 { 260 ASSERT(IrpContext); 261 ExFreeToNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, IrpContext); 262 } 263 264 static 265 PVFAT_IRP_CONTEXT 266 VfatAllocateIrpContext( 267 PDEVICE_OBJECT DeviceObject, 268 PIRP Irp) 269 { 270 PVFAT_IRP_CONTEXT IrpContext; 271 /*PIO_STACK_LOCATION Stack;*/ 272 UCHAR MajorFunction; 273 274 DPRINT("VfatAllocateIrpContext(DeviceObject %p, Irp %p)\n", DeviceObject, Irp); 275 276 ASSERT(DeviceObject); 277 ASSERT(Irp); 278 279 IrpContext = ExAllocateFromNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList); 280 if (IrpContext) 281 { 282 RtlZeroMemory(IrpContext, sizeof(VFAT_IRP_CONTEXT)); 283 IrpContext->Irp = Irp; 284 IrpContext->DeviceObject = DeviceObject; 285 IrpContext->DeviceExt = DeviceObject->DeviceExtension; 286 IrpContext->Stack = IoGetCurrentIrpStackLocation(Irp); 287 ASSERT(IrpContext->Stack); 288 MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction; 289 IrpContext->MinorFunction = IrpContext->Stack->MinorFunction; 290 IrpContext->FileObject = IrpContext->Stack->FileObject; 291 IrpContext->Flags = IRPCONTEXT_COMPLETE; 292 293 /* Easy cases that can wait */ 294 if (MajorFunction == IRP_MJ_CLEANUP || 295 MajorFunction == IRP_MJ_CREATE || 296 MajorFunction == IRP_MJ_SHUTDOWN || 297 MajorFunction == IRP_MJ_CLOSE /* likely to be fixed */) 298 { 299 SetFlag(IrpContext->Flags, IRPCONTEXT_CANWAIT); 300 } 301 /* Cases that can wait if synchronous IRP */ 302 else if ((MajorFunction == IRP_MJ_DEVICE_CONTROL || 303 MajorFunction == IRP_MJ_QUERY_INFORMATION || 304 MajorFunction == IRP_MJ_SET_INFORMATION || 305 MajorFunction == IRP_MJ_FLUSH_BUFFERS || 306 MajorFunction == IRP_MJ_LOCK_CONTROL || 307 MajorFunction == IRP_MJ_QUERY_VOLUME_INFORMATION || 308 MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION || 309 MajorFunction == IRP_MJ_DIRECTORY_CONTROL || 310 MajorFunction == IRP_MJ_WRITE || 311 MajorFunction == IRP_MJ_READ) && 312 IoIsOperationSynchronous(Irp)) 313 { 314 SetFlag(IrpContext->Flags, IRPCONTEXT_CANWAIT); 315 } 316 /* Cases that can wait if synchronous or if no FO */ 317 else if ((MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL || 318 MajorFunction == IRP_MJ_PNP) && 319 (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL || 320 IoIsOperationSynchronous(Irp))) 321 { 322 SetFlag(IrpContext->Flags, IRPCONTEXT_CANWAIT); 323 } 324 325 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE); 326 IrpContext->RefCount = 0; 327 IrpContext->PriorityBoost = IO_NO_INCREMENT; 328 } 329 return IrpContext; 330 } 331 332 static WORKER_THREAD_ROUTINE VfatDoRequest; 333 334 static 335 VOID 336 NTAPI 337 VfatDoRequest( 338 PVOID Context) 339 { 340 PVFAT_IRP_CONTEXT IrpContext = Context; 341 PDEVICE_EXTENSION DeviceExt; 342 KIRQL OldIrql; 343 344 InterlockedDecrement(&QueueCount); 345 346 if (IrpContext->Stack->FileObject != NULL) 347 { 348 DeviceExt = IrpContext->Stack->DeviceObject->DeviceExtension; 349 ObReferenceObject(DeviceExt->VolumeDevice); 350 } 351 352 do 353 { 354 DPRINT("VfatDoRequest(IrpContext %p), MajorFunction %x, %d\n", 355 IrpContext, IrpContext->MajorFunction, QueueCount); 356 VfatDispatchRequest(IrpContext); 357 IrpContext = NULL; 358 359 /* Now process any overflow items */ 360 if (DeviceExt != NULL) 361 { 362 KeAcquireSpinLock(&DeviceExt->OverflowQueueSpinLock, &OldIrql); 363 if (DeviceExt->OverflowQueueCount != 0) 364 { 365 IrpContext = CONTAINING_RECORD(RemoveHeadList(&DeviceExt->OverflowQueue), 366 VFAT_IRP_CONTEXT, 367 WorkQueueItem.List); 368 DeviceExt->OverflowQueueCount--; 369 DPRINT("Processing overflow item for IRP %p context %p (%lu)\n", 370 IrpContext->Irp, IrpContext, DeviceExt->OverflowQueueCount); 371 } 372 else 373 { 374 ASSERT(IsListEmpty(&DeviceExt->OverflowQueue)); 375 DeviceExt->PostedRequestCount--; 376 } 377 KeReleaseSpinLock(&DeviceExt->OverflowQueueSpinLock, OldIrql); 378 } 379 } while (IrpContext != NULL); 380 381 if (DeviceExt != NULL) 382 { 383 ObDereferenceObject(DeviceExt->VolumeDevice); 384 } 385 } 386 387 static 388 NTSTATUS 389 VfatQueueRequest( 390 PVFAT_IRP_CONTEXT IrpContext) 391 { 392 PDEVICE_EXTENSION DeviceExt; 393 KIRQL OldIrql; 394 BOOLEAN Overflow; 395 396 InterlockedIncrement(&QueueCount); 397 DPRINT("VfatQueueRequest(IrpContext %p), %d\n", IrpContext, QueueCount); 398 399 ASSERT(IrpContext != NULL); 400 ASSERT(IrpContext->Irp != NULL); 401 ASSERT(!(IrpContext->Flags & IRPCONTEXT_QUEUE) && 402 (IrpContext->Flags & IRPCONTEXT_COMPLETE)); 403 404 Overflow = FALSE; 405 IrpContext->Flags |= IRPCONTEXT_CANWAIT; 406 IoMarkIrpPending(IrpContext->Irp); 407 408 /* We should not block more than two worker threads per volume, 409 * or we might stop Cc from doing the work to unblock us. 410 * Add additional requests into the overflow queue instead and process 411 * them all in an existing worker thread (see VfatDoRequest above). 412 */ 413 if (IrpContext->Stack->FileObject != NULL) 414 { 415 DeviceExt = IrpContext->Stack->DeviceObject->DeviceExtension; 416 KeAcquireSpinLock(&DeviceExt->OverflowQueueSpinLock, &OldIrql); 417 if (DeviceExt->PostedRequestCount > 2) 418 { 419 DeviceExt->OverflowQueueCount++; 420 DPRINT("Queue overflow. Adding IRP %p context %p to overflow queue (%lu)\n", 421 IrpContext->Irp, IrpContext, DeviceExt->OverflowQueueCount); 422 InsertTailList(&DeviceExt->OverflowQueue, 423 &IrpContext->WorkQueueItem.List); 424 Overflow = TRUE; 425 } 426 else 427 { 428 DeviceExt->PostedRequestCount++; 429 } 430 KeReleaseSpinLock(&DeviceExt->OverflowQueueSpinLock, OldIrql); 431 } 432 433 if (!Overflow) 434 { 435 ExInitializeWorkItem(&IrpContext->WorkQueueItem, VfatDoRequest, IrpContext); 436 ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue); 437 } 438 439 return STATUS_PENDING; 440 } 441 442 PVOID 443 VfatGetUserBuffer( 444 IN PIRP Irp, 445 IN BOOLEAN Paging) 446 { 447 ASSERT(Irp); 448 449 if (Irp->MdlAddress) 450 { 451 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, (Paging ? HighPagePriority : NormalPagePriority)); 452 } 453 else 454 { 455 return Irp->UserBuffer; 456 } 457 } 458 459 NTSTATUS 460 VfatLockUserBuffer( 461 IN PIRP Irp, 462 IN ULONG Length, 463 IN LOCK_OPERATION Operation) 464 { 465 ASSERT(Irp); 466 467 if (Irp->MdlAddress) 468 { 469 return STATUS_SUCCESS; 470 } 471 472 IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp); 473 474 if (!Irp->MdlAddress) 475 { 476 return STATUS_INSUFFICIENT_RESOURCES; 477 } 478 479 _SEH2_TRY 480 { 481 MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation); 482 } 483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 484 { 485 IoFreeMdl(Irp->MdlAddress); 486 Irp->MdlAddress = NULL; 487 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 488 } 489 _SEH2_END; 490 491 return STATUS_SUCCESS; 492 } 493 494 BOOLEAN 495 VfatCheckForDismount( 496 IN PDEVICE_EXTENSION DeviceExt, 497 IN BOOLEAN Force) 498 { 499 KIRQL OldIrql; 500 ULONG UnCleanCount; 501 PVPB Vpb; 502 BOOLEAN Delete; 503 504 DPRINT1("VfatCheckForDismount(%p, %u)\n", DeviceExt, Force); 505 506 /* If the VCB is OK (not under uninitialization) and we don't force dismount, do nothing */ 507 if (BooleanFlagOn(DeviceExt->Flags, VCB_GOOD) && !Force) 508 { 509 return FALSE; 510 } 511 512 /* 513 * NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers 514 * as well as MS' fastfat, perform a comparison check of the current VCB's 515 * VPB ReferenceCount with some sort of "dangling"/"residual" open count, 516 * depending on whether or not we are in IRP_MJ_CREATE. 517 * It seems to be related to the fact that the volume root directory as 518 * well as auxiliary data stream(s) are still opened, and only these are 519 * allowed to be opened at that moment. After analysis it appears that for 520 * the ReactOS' vfatfs, this number is equal to "2". 521 */ 522 UnCleanCount = 2; 523 524 /* Lock VPB */ 525 IoAcquireVpbSpinLock(&OldIrql); 526 527 /* Reference it and check if a create is being done */ 528 Vpb = DeviceExt->IoVPB; 529 DPRINT("Vpb->ReferenceCount = %d\n", Vpb->ReferenceCount); 530 if (Vpb->ReferenceCount != UnCleanCount || DeviceExt->OpenHandleCount != 0) 531 { 532 /* If we force-unmount, copy the VPB to our local own to prepare later dismount */ 533 if (Force && Vpb->RealDevice->Vpb == Vpb && DeviceExt->SpareVPB != NULL) 534 { 535 RtlZeroMemory(DeviceExt->SpareVPB, sizeof(VPB)); 536 DeviceExt->SpareVPB->Type = IO_TYPE_VPB; 537 DeviceExt->SpareVPB->Size = sizeof(VPB); 538 DeviceExt->SpareVPB->RealDevice = DeviceExt->IoVPB->RealDevice; 539 DeviceExt->SpareVPB->DeviceObject = NULL; 540 DeviceExt->SpareVPB->Flags = DeviceExt->IoVPB->Flags & VPB_REMOVE_PENDING; 541 DeviceExt->IoVPB->RealDevice->Vpb = DeviceExt->SpareVPB; 542 DeviceExt->SpareVPB = NULL; 543 DeviceExt->IoVPB->Flags |= VPB_PERSISTENT; 544 545 /* We are uninitializing, the VCB cannot be used anymore */ 546 ClearFlag(DeviceExt->Flags, VCB_GOOD); 547 } 548 549 /* Don't do anything for now */ 550 Delete = FALSE; 551 } 552 else 553 { 554 /* Otherwise, delete the volume */ 555 Delete = TRUE; 556 557 /* Swap the VPB with our local own */ 558 if (Vpb->RealDevice->Vpb == Vpb && DeviceExt->SpareVPB != NULL) 559 { 560 RtlZeroMemory(DeviceExt->SpareVPB, sizeof(VPB)); 561 DeviceExt->SpareVPB->Type = IO_TYPE_VPB; 562 DeviceExt->SpareVPB->Size = sizeof(VPB); 563 DeviceExt->SpareVPB->RealDevice = DeviceExt->IoVPB->RealDevice; 564 DeviceExt->SpareVPB->DeviceObject = NULL; 565 DeviceExt->SpareVPB->Flags = DeviceExt->IoVPB->Flags & VPB_REMOVE_PENDING; 566 DeviceExt->IoVPB->RealDevice->Vpb = DeviceExt->SpareVPB; 567 DeviceExt->SpareVPB = NULL; 568 DeviceExt->IoVPB->Flags |= VPB_PERSISTENT; 569 570 /* We are uninitializing, the VCB cannot be used anymore */ 571 ClearFlag(DeviceExt->Flags, VCB_GOOD); 572 } 573 574 /* 575 * We defer setting the VPB's DeviceObject to NULL for later because 576 * we want to handle the closing of the internal opened meta-files. 577 */ 578 579 /* Clear the mounted and locked flags in the VPB */ 580 ClearFlag(Vpb->Flags, VPB_MOUNTED | VPB_LOCKED); 581 } 582 583 /* Release lock and return status */ 584 IoReleaseVpbSpinLock(OldIrql); 585 586 /* If we were to delete, delete volume */ 587 if (Delete) 588 { 589 LARGE_INTEGER Zero = {{0,0}}; 590 PVFATFCB Fcb; 591 592 /* We are uninitializing, the VCB cannot be used anymore */ 593 ClearFlag(DeviceExt->Flags, VCB_GOOD); 594 595 /* Invalidate and close the internal opened meta-files */ 596 if (DeviceExt->RootFcb) 597 { 598 Fcb = DeviceExt->RootFcb; 599 CcUninitializeCacheMap(Fcb->FileObject, 600 &Zero, 601 NULL); 602 ObDereferenceObject(Fcb->FileObject); 603 DeviceExt->RootFcb = NULL; 604 vfatDestroyFCB(Fcb); 605 } 606 if (DeviceExt->VolumeFcb) 607 { 608 Fcb = DeviceExt->VolumeFcb; 609 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT 610 CcUninitializeCacheMap(Fcb->FileObject, 611 &Zero, 612 NULL); 613 ObDereferenceObject(Fcb->FileObject); 614 #endif 615 DeviceExt->VolumeFcb = NULL; 616 vfatDestroyFCB(Fcb); 617 } 618 if (DeviceExt->FATFileObject) 619 { 620 Fcb = DeviceExt->FATFileObject->FsContext; 621 CcUninitializeCacheMap(DeviceExt->FATFileObject, 622 &Zero, 623 NULL); 624 DeviceExt->FATFileObject->FsContext = NULL; 625 ObDereferenceObject(DeviceExt->FATFileObject); 626 DeviceExt->FATFileObject = NULL; 627 vfatDestroyFCB(Fcb); 628 } 629 630 ASSERT(DeviceExt->OverflowQueueCount == 0); 631 ASSERT(IsListEmpty(&DeviceExt->OverflowQueue)); 632 ASSERT(DeviceExt->PostedRequestCount == 0); 633 634 /* 635 * Now that the closing of the internal opened meta-files has been 636 * handled, we can now set the VPB's DeviceObject to NULL. 637 */ 638 Vpb->DeviceObject = NULL; 639 640 /* If we have a local VPB, we'll have to delete it 641 * but we won't dismount us - something went bad before 642 */ 643 if (DeviceExt->SpareVPB) 644 { 645 ExFreePool(DeviceExt->SpareVPB); 646 } 647 /* Otherwise, delete any of the available VPB if its reference count is zero */ 648 else if (DeviceExt->IoVPB->ReferenceCount == 0) 649 { 650 ExFreePool(DeviceExt->IoVPB); 651 } 652 653 /* Remove the volume from the list */ 654 ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE); 655 RemoveEntryList(&DeviceExt->VolumeListEntry); 656 ExReleaseResourceLite(&VfatGlobalData->VolumeListLock); 657 658 /* Uninitialize the notify synchronization object */ 659 FsRtlNotifyUninitializeSync(&DeviceExt->NotifySync); 660 661 /* Release resources */ 662 ExFreePoolWithTag(DeviceExt->Statistics, TAG_STATS); 663 ExDeleteResourceLite(&DeviceExt->DirResource); 664 ExDeleteResourceLite(&DeviceExt->FatResource); 665 666 /* Dismount our device if possible */ 667 ObDereferenceObject(DeviceExt->StorageDevice); 668 IoDeleteDevice(DeviceExt->VolumeDevice); 669 } 670 671 return Delete; 672 } 673