1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 VerfySup.c 8 9 Abstract: 10 11 This module implements the Cdfs Verification routines. 12 13 14 --*/ 15 16 #include "cdprocs.h" 17 18 // 19 // The Bug check file id for this module 20 // 21 22 #define BugCheckFileId (CDFS_BUG_CHECK_VERFYSUP) 23 24 #ifdef ALLOC_PRAGMA 25 #pragma alloc_text(PAGE, CdVerifyFcbOperation) 26 #pragma alloc_text(PAGE, CdVerifyVcb) 27 #endif 28 29 _Requires_lock_held_(_Global_critical_region_) 30 NTSTATUS 31 CdPerformVerify ( 32 _Inout_ PIRP_CONTEXT IrpContext, 33 _Inout_ PIRP Irp, 34 _In_ PDEVICE_OBJECT DeviceToVerify 35 ) 36 37 /*++ 38 39 Routine Description: 40 41 This routines performs an IoVerifyVolume operation and takes the 42 appropriate action. If the verify is successful then we send the originating 43 Irp off to an Ex Worker Thread. This routine is called from the exception handler. 44 45 No file system resources are held when this routine is called. 46 47 Arguments: 48 49 Irp - The irp to send off after all is well and done. 50 51 Device - The real device needing verification. 52 53 Return Value: 54 55 None. 56 57 --*/ 58 59 { 60 PVCB Vcb; 61 NTSTATUS Status = STATUS_SUCCESS; 62 PIO_STACK_LOCATION IrpSp; 63 64 ASSERT_IRP_CONTEXT( IrpContext ); 65 ASSERT_IRP( Irp ); 66 67 // 68 // Check if this Irp has a status of Verify required and if it does 69 // then call the I/O system to do a verify. 70 // 71 // Skip the IoVerifyVolume if this is a mount or verify request 72 // itself. Trying a recursive mount will cause a deadlock with 73 // the DeviceObject->DeviceLock. 74 // 75 76 if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) && 77 ((IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) || 78 (IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME))) { 79 80 return CdFsdPostRequest( IrpContext, Irp ); 81 } 82 83 // 84 // Extract a pointer to the Vcb from the VolumeDeviceObject. 85 // Note that since we have specifically excluded mount, 86 // requests, we know that IrpSp->DeviceObject is indeed a 87 // volume device object. 88 // 89 90 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 91 92 Vcb = &CONTAINING_RECORD( IrpSp->DeviceObject, 93 VOLUME_DEVICE_OBJECT, 94 DeviceObject )->Vcb; 95 _SEH2_TRY { 96 97 // 98 // Send down the verify FSCTL. Note that this is sent to the 99 // currently mounted volume, which may not be this one. 100 // 101 // We will allow Raw to mount this volume if we were doing a 102 // an absolute DASD open. 103 // 104 105 Status = IoVerifyVolume( DeviceToVerify, CdOperationIsDasdOpen( IrpContext)); 106 107 // 108 // Acquire the Vcb so we're working with a stable VcbCondition. 109 // 110 111 CdAcquireVcbShared( IrpContext, Vcb, FALSE); 112 113 // 114 // If the verify operation completed it will return 115 // either STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly. 116 // 117 // If CdVerifyVolume encountered an error during 118 // processing, it will return that error. If we got 119 // STATUS_WRONG_VOLUME from the verify, and our volume 120 // is now mounted, commute the status to STATUS_SUCCESS. 121 // 122 123 if ((Status == STATUS_WRONG_VOLUME) && 124 (Vcb->VcbCondition == VcbMounted)) { 125 126 Status = STATUS_SUCCESS; 127 } 128 else if ((STATUS_SUCCESS == Status) && (Vcb->VcbCondition != VcbMounted)) { 129 130 // 131 // If the verify succeeded, but our volume is not mounted, 132 // then some other volume is on the device. 133 // 134 135 Status = STATUS_WRONG_VOLUME; 136 } 137 138 // 139 // Do a quick unprotected check here. The routine will do 140 // a safe check. After here we can release the resource. 141 // Note that if the volume really went away, we will be taking 142 // the Reparse path. 143 // 144 145 // 146 // If the device might need to go away then call our dismount routine. 147 // 148 149 if (((Vcb->VcbCondition == VcbNotMounted) || 150 (Vcb->VcbCondition == VcbInvalid) || 151 (Vcb->VcbCondition == VcbDismountInProgress)) && 152 (Vcb->VcbReference <= CDFS_RESIDUAL_REFERENCE)) { 153 154 CdReleaseVcb( IrpContext, Vcb); 155 156 CdAcquireCdData( IrpContext ); 157 CdCheckForDismount( IrpContext, Vcb, FALSE ); 158 CdReleaseCdData( IrpContext ); 159 } 160 else { 161 162 CdReleaseVcb( IrpContext, Vcb); 163 } 164 165 // 166 // If this is a create and the verify succeeded then complete the 167 // request with a REPARSE status. 168 // 169 170 if ((IrpContext->MajorFunction == IRP_MJ_CREATE) && 171 (IrpSp->FileObject->RelatedFileObject == NULL) && 172 ((Status == STATUS_SUCCESS) || (Status == STATUS_WRONG_VOLUME))) { 173 174 Irp->IoStatus.Information = IO_REMOUNT; 175 176 CdCompleteRequest( IrpContext, Irp, STATUS_REPARSE ); 177 Status = STATUS_REPARSE; 178 Irp = NULL; 179 IrpContext = NULL; 180 181 // 182 // If there is still an error to process then call the Io system 183 // for a popup. 184 // 185 186 } else if ((Irp != NULL) && !NT_SUCCESS( Status )) { 187 188 // 189 // Fill in the device object if required. 190 // 191 192 if (IoIsErrorUserInduced( Status ) ) { 193 194 IoSetHardErrorOrVerifyDevice( Irp, DeviceToVerify ); 195 } 196 197 CdNormalizeAndRaiseStatus( IrpContext, Status ); 198 } 199 200 // 201 // If there is still an Irp, send it off to an Ex Worker thread. 202 // 203 204 if (IrpContext != NULL) { 205 206 Status = CdFsdPostRequest( IrpContext, Irp ); 207 } 208 209 } _SEH2_EXCEPT(CdExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 210 211 // 212 // We had some trouble trying to perform the verify or raised 213 // an error ourselves. So we'll abort the I/O request with 214 // the error status that we get back from the execption code. 215 // 216 217 Status = CdProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); 218 } _SEH2_END; 219 220 return Status; 221 } 222 223 224 225 _Requires_lock_held_(_Global_critical_region_) 226 BOOLEAN 227 CdCheckForDismount ( 228 _In_ PIRP_CONTEXT IrpContext, 229 _Inout_ PVCB Vcb, 230 _In_ BOOLEAN Force 231 ) 232 233 /*++ 234 235 Routine Description: 236 237 This routine is called to check if a volume is ready for dismount. This 238 occurs when only file system references are left on the volume. 239 240 If the dismount is not currently underway and the user reference count 241 has gone to zero then we can begin the dismount. 242 243 If the dismount is in progress and there are no references left on the 244 volume (we check the Vpb for outstanding references as well to catch 245 any create calls dispatched to the file system) then we can delete 246 the Vcb. 247 248 Arguments: 249 250 Vcb - Vcb for the volume to try to dismount. 251 252 Force - Whether we will force this volume to be dismounted. 253 254 Return Value: 255 256 BOOLEAN - True if the Vcb was not gone by the time this function finished, 257 False if it was deleted. 258 259 This is only a trustworthy indication to the caller if it had the vcb 260 exclusive itself. 261 262 --*/ 263 264 { 265 BOOLEAN UnlockVcb = TRUE; 266 BOOLEAN VcbPresent = TRUE; 267 KIRQL SavedIrql; 268 269 ASSERT_IRP_CONTEXT( IrpContext ); 270 ASSERT_VCB( Vcb ); 271 272 ASSERT_EXCLUSIVE_CDDATA; 273 274 // 275 // Acquire and lock this Vcb to check the dismount state. 276 // 277 278 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE ); 279 280 // 281 // Lets get rid of any pending closes for this volume. 282 // 283 284 CdFspClose( Vcb ); 285 286 CdLockVcb( IrpContext, Vcb ); 287 288 // 289 // If the dismount is not already underway then check if the 290 // user reference count has gone to zero or we are being forced 291 // to disconnect. If so start the teardown on the Vcb. 292 // 293 294 if (Vcb->VcbCondition != VcbDismountInProgress) { 295 296 if (Vcb->VcbUserReference <= CDFS_RESIDUAL_USER_REFERENCE || Force) { 297 298 CdUnlockVcb( IrpContext, Vcb ); 299 UnlockVcb = FALSE; 300 VcbPresent = CdDismountVcb( IrpContext, Vcb ); 301 } 302 303 // 304 // If the teardown is underway and there are absolutely no references 305 // remaining then delete the Vcb. References here include the 306 // references in the Vcb and Vpb. 307 // 308 309 } else if (Vcb->VcbReference == 0) { 310 311 IoAcquireVpbSpinLock( &SavedIrql ); 312 313 // 314 // If there are no file objects and no reference counts in the 315 // Vpb we can delete the Vcb. Don't forget that we have the 316 // last reference in the Vpb. 317 // 318 319 if (Vcb->Vpb->ReferenceCount == 1) { 320 321 IoReleaseVpbSpinLock( SavedIrql ); 322 CdUnlockVcb( IrpContext, Vcb ); 323 UnlockVcb = FALSE; 324 CdDeleteVcb( IrpContext, Vcb ); 325 VcbPresent = FALSE; 326 327 } else { 328 329 IoReleaseVpbSpinLock( SavedIrql ); 330 } 331 } 332 333 // 334 // Unlock the Vcb if still held. 335 // 336 337 if (UnlockVcb) { 338 339 CdUnlockVcb( IrpContext, Vcb ); 340 } 341 342 // 343 // Release any resources still acquired. 344 // 345 346 if (VcbPresent) { 347 348 CdReleaseVcb( IrpContext, Vcb ); 349 } 350 else { 351 _Analysis_assume_lock_not_held_(Vcb->VcbResource); 352 } 353 354 return VcbPresent; 355 } 356 357 358 BOOLEAN 359 CdMarkDevForVerifyIfVcbMounted ( 360 _Inout_ PVCB Vcb 361 ) 362 363 /*++ 364 365 Routine Description: 366 367 This routine checks to see if the specified Vcb is currently mounted on 368 the device or not. If it is, it sets the verify flag on the device, if 369 not then the state is noted in the Vcb. 370 371 Arguments: 372 373 Vcb - This is the volume to check. 374 375 Return Value: 376 377 TRUE if the device has been marked for verify here, FALSE otherwise. 378 379 --*/ 380 381 { 382 BOOLEAN Marked = FALSE; 383 KIRQL SavedIrql; 384 385 IoAcquireVpbSpinLock( &SavedIrql ); 386 387 #ifdef _MSC_VER 388 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the vpb is allowed") 389 #endif 390 if (Vcb->Vpb->RealDevice->Vpb == Vcb->Vpb) { 391 392 CdMarkRealDevForVerify( Vcb->Vpb->RealDevice); 393 Marked = TRUE; 394 } 395 else { 396 397 // 398 // Flag this to avoid the VPB spinlock in future passes. 399 // 400 401 SetFlag( Vcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE); 402 } 403 404 IoReleaseVpbSpinLock( SavedIrql ); 405 406 return Marked; 407 } 408 409 410 VOID 411 CdVerifyVcb ( 412 _In_ PIRP_CONTEXT IrpContext, 413 _Inout_ PVCB Vcb 414 ) 415 416 /*++ 417 418 Routine Description: 419 420 This routine checks that the current Vcb is valid and currently mounted 421 on the device. It will raise on an error condition. 422 423 We check whether the volume needs verification and the current state 424 of the Vcb. 425 426 Arguments: 427 428 Vcb - This is the volume to verify. 429 430 Return Value: 431 432 None 433 434 --*/ 435 436 { 437 NTSTATUS Status = STATUS_SUCCESS; 438 IO_STATUS_BLOCK Iosb; 439 ULONG MediaChangeCount = 0; 440 BOOLEAN ForceVerify = FALSE; 441 BOOLEAN DevMarkedForVerify; 442 443 PAGED_CODE(); 444 445 // 446 // Fail immediately if the volume is in the progress of being dismounted 447 // or has been marked invalid. 448 // 449 450 if ((Vcb->VcbCondition == VcbInvalid) || 451 ((Vcb->VcbCondition == VcbDismountInProgress) && 452 (IrpContext->MajorFunction != IRP_MJ_CREATE))) { 453 454 if (FlagOn( Vcb->VcbState, VCB_STATE_DISMOUNTED )) { 455 456 CdRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED ); 457 458 } else { 459 460 CdRaiseStatus( IrpContext, STATUS_FILE_INVALID ); 461 } 462 } 463 464 // 465 // Capture the real device verify state. 466 // 467 468 DevMarkedForVerify = CdRealDevNeedsVerify( Vcb->Vpb->RealDevice); 469 470 if (FlagOn( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA ) && !DevMarkedForVerify) { 471 472 // 473 // If the media is removable and the verify volume flag in the 474 // device object is not set then we want to ping the device 475 // to see if it needs to be verified. 476 // 477 478 if (Vcb->VcbCondition != VcbMountInProgress) { 479 480 Status = CdPerformDevIoCtrl( IrpContext, 481 IOCTL_CDROM_CHECK_VERIFY, 482 Vcb->TargetDeviceObject, 483 &MediaChangeCount, 484 sizeof(ULONG), 485 FALSE, 486 FALSE, 487 &Iosb ); 488 489 if (Iosb.Information != sizeof(ULONG)) { 490 491 // 492 // Be safe about the count in case the driver didn't fill it in 493 // 494 495 MediaChangeCount = 0; 496 } 497 498 // 499 // There are four cases when we want to do a verify. These are the 500 // first three. 501 // 502 // 1. We are mounted, and the device has become empty 503 // 2. The device has returned verify required (=> DO_VERIFY_VOL flag is 504 // set, but could be due to hardware condition) 505 // 3. Media change count doesn't match the one in the Vcb 506 // 507 508 if (((Vcb->VcbCondition == VcbMounted) && 509 CdIsRawDevice( IrpContext, Status )) 510 || 511 (Status == STATUS_VERIFY_REQUIRED) 512 || 513 (NT_SUCCESS(Status) && 514 (Vcb->MediaChangeCount != MediaChangeCount))) { 515 516 // 517 // If we are currently the volume on the device then it is our 518 // responsibility to set the verify flag. If we're not on the device, 519 // then we shouldn't touch the flag. 520 // 521 522 if (!FlagOn( Vcb->VcbState, VCB_STATE_VPB_NOT_ON_DEVICE) && 523 !DevMarkedForVerify) { 524 525 DevMarkedForVerify = CdMarkDevForVerifyIfVcbMounted( Vcb); 526 } 527 528 ForceVerify = TRUE; 529 530 // 531 // NOTE that we no longer update the media change count here. We 532 // do so only when we've actually completed a verify at a particular 533 // change count value. 534 // 535 } 536 } 537 538 // 539 // This is the 4th verify case. 540 // 541 // We ALWAYS force CREATE requests on unmounted volumes through the 542 // verify path. These requests could have been in limbo between 543 // IoCheckMountedVpb and us when a verify/mount took place and caused 544 // a completely different fs/volume to be mounted. In this case the 545 // checks above may not have caught the condition, since we may already 546 // have verified (wrong volume) and decided that we have nothing to do. 547 // We want the requests to be re routed to the currently mounted volume, 548 // since they were directed at the 'drive', not our volume. 549 // 550 551 if (NT_SUCCESS( Status) && !ForceVerify && !DevMarkedForVerify && 552 (IrpContext->MajorFunction == IRP_MJ_CREATE)) { 553 554 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->Irp); 555 556 ForceVerify = (IrpSp->FileObject->RelatedFileObject == NULL) && 557 ((Vcb->VcbCondition == VcbDismountInProgress) || 558 (Vcb->VcbCondition == VcbNotMounted)); 559 560 // 561 // Note that we don't touch the device verify flag here. It required 562 // it would have been caught and set by the first set of checks. 563 // 564 } 565 } 566 567 // 568 // Raise the verify / error if neccessary. 569 // 570 571 if (ForceVerify || DevMarkedForVerify || !NT_SUCCESS( Status)) { 572 573 IoSetHardErrorOrVerifyDevice( IrpContext->Irp, 574 Vcb->Vpb->RealDevice ); 575 576 CdRaiseStatus( IrpContext, (ForceVerify || DevMarkedForVerify) 577 ? STATUS_VERIFY_REQUIRED 578 : Status); 579 } 580 581 // 582 // Based on the condition of the Vcb we'll either return to our 583 // caller or raise an error condition 584 // 585 586 switch (Vcb->VcbCondition) { 587 588 case VcbNotMounted: 589 590 IoSetHardErrorOrVerifyDevice( IrpContext->Irp, Vcb->Vpb->RealDevice ); 591 592 CdRaiseStatus( IrpContext, STATUS_WRONG_VOLUME ); 593 break; 594 595 case VcbInvalid: 596 case VcbDismountInProgress: 597 598 if (FlagOn( Vcb->VcbState, VCB_STATE_DISMOUNTED )) { 599 600 CdRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED ); 601 602 } else { 603 604 CdRaiseStatus( IrpContext, STATUS_FILE_INVALID ); 605 } 606 break; 607 608 /* ReactOS Change: GCC "enumeration value not handled in switch" */ 609 default: break; 610 } 611 } 612 613 614 BOOLEAN 615 CdVerifyFcbOperation ( 616 _In_opt_ PIRP_CONTEXT IrpContext, 617 _In_ PFCB Fcb 618 ) 619 620 /*++ 621 622 Routine Description: 623 624 This routine is called to verify that the state of the Fcb is valid 625 to allow the current operation to continue. We use the state of the 626 Vcb, target device and type of operation to determine this. 627 628 Arguments: 629 630 IrpContext - IrpContext for the request. If not present then we 631 were called from the fast IO path. 632 633 Fcb - Fcb to perform the request on. 634 635 Return Value: 636 637 BOOLEAN - TRUE if the request can continue, FALSE otherwise. 638 639 --*/ 640 641 { 642 PVCB Vcb = Fcb->Vcb; 643 PDEVICE_OBJECT RealDevice = Vcb->Vpb->RealDevice; 644 PIRP Irp; 645 646 PAGED_CODE(); 647 648 // 649 // Check that the fileobject has not been cleaned up. 650 // 651 652 if ( ARGUMENT_PRESENT( IrpContext )) { 653 654 PFILE_OBJECT FileObject; 655 656 Irp = IrpContext->Irp; 657 FileObject = IoGetCurrentIrpStackLocation( Irp)->FileObject; 658 659 if ( FileObject && FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE)) { 660 661 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 662 663 // 664 // Following FAT, we allow certain operations even on cleaned up 665 // file objects. Everything else, we fail. 666 // 667 668 if ( (FlagOn(Irp->Flags, IRP_PAGING_IO)) || 669 (IrpSp->MajorFunction == IRP_MJ_CLOSE ) || 670 (IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) || 671 ( (IrpSp->MajorFunction == IRP_MJ_READ) && 672 FlagOn(IrpSp->MinorFunction, IRP_MN_COMPLETE) ) ) { 673 674 NOTHING; 675 676 } else { 677 678 CdRaiseStatus( IrpContext, STATUS_FILE_CLOSED ); 679 } 680 } 681 } 682 683 // 684 // Fail immediately if the volume is in the progress of being dismounted 685 // or has been marked invalid. 686 // 687 688 if ((Vcb->VcbCondition == VcbInvalid) || 689 (Vcb->VcbCondition == VcbDismountInProgress)) { 690 691 if (ARGUMENT_PRESENT( IrpContext )) { 692 693 if (FlagOn( Vcb->VcbState, VCB_STATE_DISMOUNTED )) { 694 695 CdRaiseStatus( IrpContext, STATUS_VOLUME_DISMOUNTED ); 696 697 } else { 698 699 CdRaiseStatus( IrpContext, STATUS_FILE_INVALID ); 700 } 701 } 702 703 return FALSE; 704 } 705 706 // 707 // Always fail if the volume needs to be verified. 708 // 709 710 if (CdRealDevNeedsVerify( RealDevice)) { 711 712 if (ARGUMENT_PRESENT( IrpContext )) { 713 714 IoSetHardErrorOrVerifyDevice( IrpContext->Irp, 715 RealDevice ); 716 717 CdRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED ); 718 } 719 720 return FALSE; 721 722 // 723 // 724 // All operations are allowed on mounted. 725 // 726 727 } else if ((Vcb->VcbCondition == VcbMounted) || 728 (Vcb->VcbCondition == VcbMountInProgress)) { 729 730 return TRUE; 731 732 // 733 // Fail all requests for fast Io on other Vcb conditions. 734 // 735 736 } else if (!ARGUMENT_PRESENT( IrpContext )) { 737 738 return FALSE; 739 740 // 741 // The remaining case is VcbNotMounted. 742 // Mark the device to be verified and raise WRONG_VOLUME. 743 // 744 745 } else if (Vcb->VcbCondition == VcbNotMounted) { 746 747 IoSetHardErrorOrVerifyDevice( IrpContext->Irp, RealDevice ); 748 CdRaiseStatus( IrpContext, STATUS_WRONG_VOLUME ); 749 750 // return FALSE; // unreachable code 751 } 752 753 return TRUE; 754 } 755 756 757 758 _Requires_lock_held_(_Global_critical_region_) 759 BOOLEAN 760 CdDismountVcb ( 761 _In_ PIRP_CONTEXT IrpContext, 762 _Inout_ PVCB Vcb 763 ) 764 765 /*++ 766 767 Routine Description: 768 769 This routine is called when all of the user references to a volume are 770 gone. We will initiate all of the teardown any system resources. 771 772 If all of the references to this volume are gone at the end of this routine 773 then we will complete the teardown of this Vcb and mark the current Vpb 774 as not mounted. Otherwise we will allocated a new Vpb for this device 775 and keep the current Vpb attached to the Vcb. 776 777 Arguments: 778 779 Vcb - Vcb for the volume to dismount. 780 781 Return Value: 782 783 BOOLEAN - TRUE if we didn't delete the Vcb, FALSE otherwise. 784 785 --*/ 786 787 { 788 PVPB OldVpb; 789 BOOLEAN VcbPresent = TRUE; 790 KIRQL SavedIrql; 791 792 BOOLEAN FinalReference; 793 794 ASSERT_EXCLUSIVE_CDDATA; 795 ASSERT_EXCLUSIVE_VCB( Vcb ); 796 797 CdLockVcb( IrpContext, Vcb ); 798 799 // 800 // We should only take this path once. 801 // 802 803 NT_ASSERT( Vcb->VcbCondition != VcbDismountInProgress ); 804 805 // 806 // Mark the Vcb as DismountInProgress. 807 // 808 809 Vcb->VcbCondition = VcbDismountInProgress; 810 811 if (Vcb->XASector != NULL) { 812 813 CdFreePool( &Vcb->XASector ); 814 Vcb->XASector = 0; 815 Vcb->XADiskOffset = 0; 816 } 817 818 // 819 // Remove our reference to the internal Fcb's. The Fcb's will then 820 // be removed in the purge path below. 821 // 822 823 if (Vcb->RootIndexFcb != NULL) { 824 825 Vcb->RootIndexFcb->FcbReference -= 1; 826 Vcb->RootIndexFcb->FcbUserReference -= 1; 827 } 828 829 if (Vcb->PathTableFcb != NULL) { 830 831 Vcb->PathTableFcb->FcbReference -= 1; 832 Vcb->PathTableFcb->FcbUserReference -= 1; 833 } 834 835 if (Vcb->VolumeDasdFcb != NULL) { 836 837 Vcb->VolumeDasdFcb->FcbReference -= 1; 838 Vcb->VolumeDasdFcb->FcbUserReference -= 1; 839 } 840 841 CdUnlockVcb( IrpContext, Vcb ); 842 843 // 844 // Purge the volume. 845 // 846 847 CdPurgeVolume( IrpContext, Vcb, TRUE ); 848 849 // 850 // Empty the delayed and async close queues. 851 // 852 853 CdFspClose( Vcb ); 854 855 OldVpb = Vcb->Vpb; 856 857 // 858 // Remove the mount volume reference. 859 // 860 861 CdLockVcb( IrpContext, Vcb ); 862 Vcb->VcbReference -= 1; 863 864 // 865 // Acquire the Vpb spinlock to check for Vpb references. 866 // 867 868 IoAcquireVpbSpinLock( &SavedIrql ); 869 870 // 871 // Remember if this is the last reference on this Vcb. We incremented 872 // the count on the Vpb earlier so we get one last crack it. If our 873 // reference has gone to zero but the vpb reference count is greater 874 // than zero then the Io system will be responsible for deleting the 875 // Vpb. 876 // 877 878 FinalReference = (BOOLEAN) ((Vcb->VcbReference == 0) && 879 (OldVpb->ReferenceCount == 1)); 880 881 // 882 // There is a reference count in the Vpb and in the Vcb. We have 883 // incremented the reference count in the Vpb to make sure that 884 // we have last crack at it. If this is a failed mount then we 885 // want to return the Vpb to the IO system to use for the next 886 // mount request. 887 // 888 889 #ifdef _MSC_VER 890 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the vpb is allowed") 891 #endif 892 if (OldVpb->RealDevice->Vpb == OldVpb) { 893 894 // 895 // If not the final reference then swap out the Vpb. We must 896 // preserve the REMOVE_PENDING flag so that the device is 897 // not remounted in the middle of a PnP remove operation. 898 // 899 900 if (!FinalReference) { 901 902 NT_ASSERT( Vcb->SwapVpb != NULL ); 903 904 Vcb->SwapVpb->Type = IO_TYPE_VPB; 905 Vcb->SwapVpb->Size = sizeof( VPB ); 906 907 #ifdef _MSC_VER 908 #pragma prefast(push) 909 #pragma prefast(disable: 28175, "this is a filesystem driver, touching the vpb is allowed") 910 #endif 911 Vcb->SwapVpb->RealDevice = OldVpb->RealDevice; 912 Vcb->SwapVpb->RealDevice->Vpb = Vcb->SwapVpb; 913 #ifdef _MSC_VER 914 #pragma prefast(pop) 915 #endif 916 917 Vcb->SwapVpb->Flags = FlagOn( OldVpb->Flags, VPB_REMOVE_PENDING ); 918 919 IoReleaseVpbSpinLock( SavedIrql ); 920 921 // 922 // Indicate we used up the swap. 923 // 924 925 Vcb->SwapVpb = NULL; 926 927 CdUnlockVcb( IrpContext, Vcb ); 928 929 // 930 // We want to leave the Vpb for the IO system. Mark it 931 // as being not mounted. Go ahead and delete the Vcb as 932 // well. 933 // 934 935 } else { 936 937 // 938 // Make sure to remove the last reference on the Vpb. 939 // 940 941 OldVpb->ReferenceCount -= 1; 942 943 OldVpb->DeviceObject = NULL; 944 ClearFlag( Vcb->Vpb->Flags, VPB_MOUNTED ); 945 ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED ); 946 947 // 948 // Clear the Vpb flag so we know not to delete it. 949 // 950 951 Vcb->Vpb = NULL; 952 953 IoReleaseVpbSpinLock( SavedIrql ); 954 CdUnlockVcb( IrpContext, Vcb ); 955 CdDeleteVcb( IrpContext, Vcb ); 956 VcbPresent = FALSE; 957 } 958 959 // 960 // Someone has already swapped in a new Vpb. If this is the final reference 961 // then the file system is responsible for deleting the Vpb. 962 // 963 964 } else if (FinalReference) { 965 966 // 967 // Make sure to remove the last reference on the Vpb. 968 // 969 970 OldVpb->ReferenceCount -= 1; 971 972 IoReleaseVpbSpinLock( SavedIrql ); 973 CdUnlockVcb( IrpContext, Vcb ); 974 CdDeleteVcb( IrpContext, Vcb ); 975 VcbPresent = FALSE; 976 977 // 978 // The current Vpb is no longer the Vpb for the device (the IO system 979 // has already allocated a new one). We leave our reference in the 980 // Vpb and will be responsible for deleting it at a later time. 981 // 982 983 } else { 984 985 IoReleaseVpbSpinLock( SavedIrql ); 986 CdUnlockVcb( IrpContext, Vcb ); 987 } 988 989 // 990 // Let our caller know whether the Vcb is still present. 991 // 992 993 return VcbPresent; 994 } 995 996