1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 ResrcSup.c 8 9 Abstract: 10 11 This module implements the Fat Resource acquisition routines 12 13 14 --*/ 15 16 #include "fatprocs.h" 17 18 #ifdef ALLOC_PRAGMA 19 #pragma alloc_text(PAGE, FatAcquireFcbForLazyWrite) 20 #pragma alloc_text(PAGE, FatAcquireFcbForReadAhead) 21 #pragma alloc_text(PAGE, FatAcquireExclusiveFcb) 22 #pragma alloc_text(PAGE, FatAcquireSharedFcb) 23 #pragma alloc_text(PAGE, FatAcquireSharedFcbWaitForEx) 24 #pragma alloc_text(PAGE, FatAcquireExclusiveVcb_Real) 25 #pragma alloc_text(PAGE, FatAcquireSharedVcb) 26 #pragma alloc_text(PAGE, FatNoOpAcquire) 27 #pragma alloc_text(PAGE, FatNoOpRelease) 28 #pragma alloc_text(PAGE, FatReleaseFcbFromLazyWrite) 29 #pragma alloc_text(PAGE, FatReleaseFcbFromReadAhead) 30 #pragma alloc_text(PAGE, FatAcquireForCcFlush) 31 #pragma alloc_text(PAGE, FatReleaseForCcFlush) 32 #pragma alloc_text(PAGE, FatFilterCallbackAcquireForCreateSection) 33 #endif 34 35 _Requires_lock_held_(_Global_critical_region_) 36 _When_(return != FALSE && NoOpCheck != FALSE, _Acquires_exclusive_lock_(Vcb->Resource)) 37 FINISHED 38 FatAcquireExclusiveVcb_Real ( 39 IN PIRP_CONTEXT IrpContext, 40 IN PVCB Vcb, 41 IN BOOLEAN NoOpCheck 42 ) 43 44 /*++ 45 46 Routine Description: 47 48 This routine acquires exclusive access to the Vcb. 49 50 After we acquire the resource check to see if this operation is legal. 51 If it isn't (ie. we get an exception), release the resource. 52 53 Arguments: 54 55 Vcb - Supplies the Vcb to acquire 56 57 NoOpCheck - if TRUE then don't do any verification of the request/volume state. 58 59 Return Value: 60 61 FINISHED - TRUE if we have the resource and FALSE if we needed to block 62 for the resource but Wait is FALSE. 63 64 --*/ 65 66 { 67 PAGED_CODE(); 68 69 #ifdef _MSC_VER 70 #pragma prefast( suppress: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" ) 71 #endif 72 if (ExAcquireResourceExclusiveLite( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { 73 74 if (!NoOpCheck) { 75 76 _SEH2_TRY { 77 78 FatVerifyOperationIsLegal( IrpContext ); 79 80 } _SEH2_FINALLY { 81 82 if ( _SEH2_AbnormalTermination() ) { 83 84 FatReleaseVcb( IrpContext, Vcb ); 85 } 86 } _SEH2_END; 87 } 88 89 return TRUE; 90 } 91 92 return FALSE; 93 } 94 95 _Requires_lock_held_(_Global_critical_region_) 96 _When_(return != 0, _Acquires_shared_lock_(Vcb->Resource)) 97 FINISHED 98 FatAcquireSharedVcb ( 99 IN PIRP_CONTEXT IrpContext, 100 IN PVCB Vcb 101 ) 102 103 /*++ 104 105 Routine Description: 106 107 This routine acquires shared access to the Vcb. 108 109 After we acquire the resource check to see if this operation is legal. 110 If it isn't (ie. we get an exception), release the resource. 111 112 Arguments: 113 114 Vcb - Supplies the Vcb to acquire 115 116 Return Value: 117 118 FINISHED - TRUE if we have the resource and FALSE if we needed to block 119 for the resource but Wait is FALSE. 120 121 --*/ 122 123 { 124 PAGED_CODE(); 125 126 if (ExAcquireResourceSharedLite( &Vcb->Resource, 127 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { 128 129 _SEH2_TRY { 130 131 FatVerifyOperationIsLegal( IrpContext ); 132 133 } _SEH2_FINALLY { 134 135 if ( _SEH2_AbnormalTermination() ) { 136 137 FatReleaseVcb( IrpContext, Vcb ); 138 } 139 } _SEH2_END; 140 141 return TRUE; 142 } 143 144 return FALSE; 145 } 146 147 _Requires_lock_held_(_Global_critical_region_) 148 _Acquires_exclusive_lock_(*Fcb->Header.Resource) 149 FINISHED 150 FatAcquireExclusiveFcb ( 151 IN PIRP_CONTEXT IrpContext, 152 IN PFCB Fcb 153 ) 154 155 /*++ 156 157 Routine Description: 158 159 This routine acquires exclusive access to the Fcb. 160 161 After we acquire the resource check to see if this operation is legal. 162 If it isn't (ie. we get an exception), release the resource. 163 164 Arguments: 165 166 Fcb - Supplies the Fcb to acquire 167 168 Return Value: 169 170 FINISHED - TRUE if we have the resource and FALSE if we needed to block 171 for the resource but Wait is FALSE. 172 173 --*/ 174 175 { 176 PAGED_CODE(); 177 178 RetryFcbExclusive: 179 180 #ifdef _MSC_VER 181 #pragma prefast( suppress: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" ) 182 #endif 183 if (ExAcquireResourceExclusiveLite( Fcb->Header.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { 184 185 // 186 // Check for anything other than a non-cached write if the 187 // async count is non-zero in the Fcb, or if others are waiting 188 // for the resource. Then wait for all outstanding I/O to finish, 189 // drop the resource, and wait again. 190 // 191 192 if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) && 193 ((IrpContext->MajorFunction != IRP_MJ_WRITE) || 194 !FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) || 195 (ExGetSharedWaiterCount(Fcb->Header.Resource) != 0) || 196 (ExGetExclusiveWaiterCount(Fcb->Header.Resource) != 0))) { 197 198 KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent, 199 Executive, 200 KernelMode, 201 FALSE, 202 (PLARGE_INTEGER) NULL ); 203 204 FatReleaseFcb( IrpContext, Fcb ); 205 206 goto RetryFcbExclusive; 207 } 208 209 _SEH2_TRY { 210 211 FatVerifyOperationIsLegal( IrpContext ); 212 213 } _SEH2_FINALLY { 214 215 if ( _SEH2_AbnormalTermination() ) { 216 217 FatReleaseFcb( IrpContext, Fcb ); 218 } 219 } _SEH2_END; 220 221 return TRUE; 222 } 223 224 return FALSE; 225 } 226 227 228 _Requires_lock_held_(_Global_critical_region_) 229 _Acquires_shared_lock_(*Fcb->Header.Resource) 230 FINISHED 231 FatAcquireSharedFcb ( 232 IN PIRP_CONTEXT IrpContext, 233 IN PFCB Fcb 234 ) 235 236 /*++ 237 238 Routine Description: 239 240 This routine acquires shared access to the Fcb. 241 242 After we acquire the resource check to see if this operation is legal. 243 If it isn't (ie. we get an exception), release the resource. 244 245 Arguments: 246 247 Fcb - Supplies the Fcb to acquire 248 249 Return Value: 250 251 FINISHED - TRUE if we have the resource and FALSE if we needed to block 252 for the resource but Wait is FALSE. 253 254 --*/ 255 256 { 257 PAGED_CODE(); 258 259 RetryFcbShared: 260 261 if (ExAcquireResourceSharedLite( Fcb->Header.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { 262 263 // 264 // Check for anything other than a non-cached write if the 265 // async count is non-zero in the Fcb, or if others are waiting 266 // for the resource. Then wait for all outstanding I/O to finish, 267 // drop the resource, and wait again. 268 // 269 270 if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) && 271 ((IrpContext->MajorFunction != IRP_MJ_WRITE) || 272 !FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) || 273 (ExGetSharedWaiterCount(Fcb->Header.Resource) != 0) || 274 (ExGetExclusiveWaiterCount(Fcb->Header.Resource) != 0))) { 275 276 KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent, 277 Executive, 278 KernelMode, 279 FALSE, 280 (PLARGE_INTEGER) NULL ); 281 282 FatReleaseFcb( IrpContext, Fcb ); 283 284 goto RetryFcbShared; 285 } 286 287 _SEH2_TRY { 288 289 FatVerifyOperationIsLegal( IrpContext ); 290 291 } _SEH2_FINALLY { 292 293 if ( _SEH2_AbnormalTermination() ) { 294 295 FatReleaseFcb( IrpContext, Fcb ); 296 } 297 } _SEH2_END; 298 299 300 return TRUE; 301 302 } else { 303 304 return FALSE; 305 } 306 } 307 308 309 _Requires_lock_held_(_Global_critical_region_) 310 _When_(return != 0, _Acquires_shared_lock_(*Fcb->Header.Resource)) 311 FINISHED 312 FatAcquireSharedFcbWaitForEx ( 313 IN PIRP_CONTEXT IrpContext, 314 IN PFCB Fcb 315 ) 316 317 /*++ 318 319 Routine Description: 320 321 This routine acquires shared access to the Fcb, waiting first for any 322 exclusive accessors to get the Fcb first. 323 324 After we acquire the resource check to see if this operation is legal. 325 If it isn't (ie. we get an exception), release the resource. 326 327 Arguments: 328 329 Fcb - Supplies the Fcb to acquire 330 331 Return Value: 332 333 FINISHED - TRUE if we have the resource and FALSE if we needed to block 334 for the resource but Wait is FALSE. 335 336 --*/ 337 338 { 339 PAGED_CODE(); 340 341 NT_ASSERT( FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) ); 342 NT_ASSERT( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); 343 344 RetryFcbSharedWaitEx: 345 346 if (ExAcquireSharedWaitForExclusive( Fcb->Header.Resource, FALSE )) { 347 348 // 349 // Check for anything other than a non-cached write if the 350 // async count is non-zero in the Fcb. Then wait for all 351 // outstanding I/O to finish, drop the resource, and wait again. 352 // 353 354 if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) && 355 (IrpContext->MajorFunction != IRP_MJ_WRITE)) { 356 357 KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent, 358 Executive, 359 KernelMode, 360 FALSE, 361 (PLARGE_INTEGER) NULL ); 362 363 FatReleaseFcb( IrpContext, Fcb ); 364 365 goto RetryFcbSharedWaitEx; 366 } 367 368 _SEH2_TRY { 369 370 FatVerifyOperationIsLegal( IrpContext ); 371 372 } _SEH2_FINALLY { 373 374 if ( _SEH2_AbnormalTermination() ) { 375 376 FatReleaseFcb( IrpContext, Fcb ); 377 } 378 } _SEH2_END; 379 380 381 return TRUE; 382 383 } else { 384 385 return FALSE; 386 } 387 } 388 389 390 _Requires_lock_held_(_Global_critical_region_) 391 BOOLEAN 392 NTAPI 393 FatAcquireFcbForLazyWrite ( 394 IN PVOID Fcb, 395 IN BOOLEAN Wait 396 ) 397 398 /*++ 399 400 Routine Description: 401 402 The address of this routine is specified when creating a CacheMap for 403 a file. It is subsequently called by the Lazy Writer prior to its 404 performing lazy writes to the file. 405 406 Arguments: 407 408 Fcb - The Fcb which was specified as a context parameter for this 409 routine. 410 411 Wait - TRUE if the caller is willing to block. 412 413 Return Value: 414 415 FALSE - if Wait was specified as FALSE and blocking would have 416 been required. The Fcb is not acquired. 417 418 TRUE - if the Fcb has been acquired 419 420 --*/ 421 422 { 423 PAGED_CODE(); 424 425 // 426 // Check here for the EA File. It turns out we need the normal 427 // resource shared in this case. Otherwise we take the paging 428 // I/O resource shared. 429 // 430 431 // 432 // Note that we do not need to disable APC delivery to guard 433 // against a rogue user issuing a suspend APC. That is because 434 // it is guaranteed that the caller is either in the system context, 435 // to which a user cannot deliver a suspend APC, or the caller has 436 // already disabled kernel APC delivery before calling. This is true 437 // for all the other pre-acquire routines as well. 438 // 439 440 if (!ExAcquireResourceSharedLite( Fcb == ((PFCB)Fcb)->Vcb->EaFcb ? 441 ((PFCB)Fcb)->Header.Resource : 442 ((PFCB)Fcb)->Header.PagingIoResource, 443 Wait )) { 444 445 return FALSE; 446 } 447 448 // 449 // We assume the Lazy Writer only acquires this Fcb once. 450 // Therefore, it should be guaranteed that this flag is currently 451 // clear (the ASSERT), and then we will set this flag, to insure 452 // that the Lazy Writer will never try to advance Valid Data, and 453 // also not deadlock by trying to get the Fcb exclusive. 454 // 455 456 457 NT_ASSERT( NodeType(((PFCB)Fcb)) == FAT_NTC_FCB ); 458 NT_ASSERT( ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread == NULL ); 459 460 ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread = PsGetCurrentThread(); 461 462 NT_ASSERT( NULL != PsGetCurrentThread() ); 463 464 if (NULL == FatData.LazyWriteThread) { 465 466 FatData.LazyWriteThread = PsGetCurrentThread(); 467 } 468 469 // 470 // This is a kludge because Cc is really the top level. When it 471 // enters the file system, we will think it is a resursive call 472 // and complete the request with hard errors or verify. It will 473 // then have to deal with them, somehow.... 474 // 475 476 NT_ASSERT(IoGetTopLevelIrp() == NULL); 477 478 IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 479 480 return TRUE; 481 } 482 483 484 _Requires_lock_held_(_Global_critical_region_) 485 VOID 486 NTAPI 487 FatReleaseFcbFromLazyWrite ( 488 IN PVOID Fcb 489 ) 490 491 /*++ 492 493 Routine Description: 494 495 The address of this routine is specified when creating a CacheMap for 496 a file. It is subsequently called by the Lazy Writer after its 497 performing lazy writes to the file. 498 499 Arguments: 500 501 Fcb - The Fcb which was specified as a context parameter for this 502 routine. 503 504 Return Value: 505 506 None 507 508 --*/ 509 510 { 511 PAGED_CODE(); 512 513 // 514 // Assert that this really is an fcb and that this thread really owns 515 // the lazy writer mark in the fcb. 516 // 517 518 NT_ASSERT( NodeType(((PFCB)Fcb)) == FAT_NTC_FCB ); 519 NT_ASSERT( NULL != PsGetCurrentThread() ); 520 NT_ASSERT( ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread == PsGetCurrentThread() ); 521 522 // 523 // Release the lazy writer mark. 524 // 525 526 ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread = NULL; 527 528 // 529 // Check here for the EA File. It turns out we needed the normal 530 // resource shared in this case. Otherwise it was the PagingIoResource. 531 // 532 533 ExReleaseResourceLite( Fcb == ((PFCB)Fcb)->Vcb->EaFcb ? 534 ((PFCB)Fcb)->Header.Resource : 535 ((PFCB)Fcb)->Header.PagingIoResource ); 536 537 // 538 // Clear the kludge at this point. 539 // 540 541 NT_ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 542 543 IoSetTopLevelIrp( NULL ); 544 545 return; 546 } 547 548 549 _Requires_lock_held_(_Global_critical_region_) 550 BOOLEAN 551 NTAPI 552 FatAcquireFcbForReadAhead ( 553 IN PVOID Fcb, 554 IN BOOLEAN Wait 555 ) 556 557 /*++ 558 559 Routine Description: 560 561 The address of this routine is specified when creating a CacheMap for 562 a file. It is subsequently called by the Lazy Writer prior to its 563 performing read ahead to the file. 564 565 Arguments: 566 567 Fcb - The Fcb which was specified as a context parameter for this 568 routine. 569 570 Wait - TRUE if the caller is willing to block. 571 572 Return Value: 573 574 FALSE - if Wait was specified as FALSE and blocking would have 575 been required. The Fcb is not acquired. 576 577 TRUE - if the Fcb has been acquired 578 579 --*/ 580 581 { 582 PAGED_CODE(); 583 584 // 585 // We acquire the normal file resource shared here to synchronize 586 // correctly with purges. 587 // 588 589 // 590 // Note that we do not need to disable APC delivery to guard 591 // against a rogue user issuing a suspend APC. That is because 592 // it is guaranteed that the caller is either in the system context, 593 // to which a user cannot deliver a suspend APC, or the caller has 594 // already disabled kernel APC delivery before calling. This is true 595 // for all the other pre-acquire routines as well. 596 // 597 598 if (!ExAcquireResourceSharedLite( ((PFCB)Fcb)->Header.Resource, 599 Wait )) { 600 601 return FALSE; 602 } 603 604 // 605 // This is a kludge because Cc is really the top level. We it 606 // enters the file system, we will think it is a resursive call 607 // and complete the request with hard errors or verify. It will 608 // have to deal with them, somehow.... 609 // 610 611 NT_ASSERT(IoGetTopLevelIrp() == NULL); 612 613 IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 614 615 return TRUE; 616 } 617 618 619 _Requires_lock_held_(_Global_critical_region_) 620 VOID 621 NTAPI 622 FatReleaseFcbFromReadAhead ( 623 IN PVOID Fcb 624 ) 625 626 /*++ 627 628 Routine Description: 629 630 The address of this routine is specified when creating a CacheMap for 631 a file. It is subsequently called by the Lazy Writer after its 632 read ahead. 633 634 Arguments: 635 636 Fcb - The Fcb which was specified as a context parameter for this 637 routine. 638 639 Return Value: 640 641 None 642 643 --*/ 644 645 { 646 PAGED_CODE(); 647 648 // 649 // Clear the kludge at this point. 650 // 651 652 NT_ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 653 654 IoSetTopLevelIrp( NULL ); 655 656 ExReleaseResourceLite( ((PFCB)Fcb)->Header.Resource ); 657 658 return; 659 } 660 661 662 _Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH) 663 _Requires_lock_held_(_Global_critical_region_) 664 NTSTATUS 665 NTAPI 666 FatAcquireForCcFlush ( 667 IN PFILE_OBJECT FileObject, 668 IN PDEVICE_OBJECT DeviceObject 669 ) 670 { 671 PFCB Fcb; 672 PCCB Ccb; 673 PVCB Vcb; 674 PFSRTL_COMMON_FCB_HEADER Header; 675 TYPE_OF_OPEN Type; 676 677 PAGED_CODE(); 678 UNREFERENCED_PARAMETER( DeviceObject ); 679 680 // 681 // Once again, the hack for making this look like 682 // a recursive call if needed. We cannot let ourselves 683 // verify under something that has resources held. 684 // 685 // This value is good. We should never try to acquire 686 // the file this way underneath of the cache. 687 // 688 689 NT_ASSERT( IoGetTopLevelIrp() != (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP ); 690 691 if (IoGetTopLevelIrp() == NULL) { 692 693 IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 694 } 695 696 // 697 // Time for some exposition. 698 // 699 // Lockorder for FAT is main->bcb->pagingio. Invert this at your obvious peril. 700 // The default logic for AcquireForCcFlush breaks this since in writethrough 701 // unpinrepinned we will grab the bcb then Mm will use the callback (which 702 // orders us with respect to the MmCollidedFlushEvent) to help us. If for 703 // directories/ea we then grab the main we are out of order. 704 // 705 // Fortunately, we do not need main. We only need paging - just look at the write 706 // path. This is basic pre-acquisition. 707 // 708 // Regular files require both resources, and are safe since we never pin them. 709 // 710 711 // 712 // Note that we do not need to disable APC delivery to guard 713 // against a rogue user issuing a suspend APC. That is because 714 // it is guaranteed that the caller is either in the system context, 715 // to which a user cannot deliver a suspend APC, or the caller has 716 // already disabled kernel APC delivery before calling. This is true 717 // for all the other pre-acquire routines as well. 718 // 719 720 Type = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); 721 Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext; 722 723 if (Type < DirectoryFile) { 724 725 if (Header->Resource) { 726 727 if (!ExIsResourceAcquiredSharedLite( Header->Resource )) { 728 729 ExAcquireResourceExclusiveLite( Header->Resource, TRUE ); 730 731 } else { 732 733 ExAcquireResourceSharedLite( Header->Resource, TRUE ); 734 } 735 } 736 } 737 738 if (Header->PagingIoResource) { 739 740 ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE ); 741 } 742 743 return STATUS_SUCCESS; 744 } 745 746 747 _Requires_lock_held_(_Global_critical_region_) 748 NTSTATUS 749 NTAPI 750 FatReleaseForCcFlush ( 751 IN PFILE_OBJECT FileObject, 752 IN PDEVICE_OBJECT DeviceObject 753 ) 754 { 755 PFCB Fcb; 756 PCCB Ccb; 757 PVCB Vcb; 758 PFSRTL_COMMON_FCB_HEADER Header; 759 TYPE_OF_OPEN Type; 760 761 PAGED_CODE(); 762 UNREFERENCED_PARAMETER( DeviceObject ); 763 764 // 765 // Clear up our hint. 766 // 767 768 if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) { 769 770 IoSetTopLevelIrp( NULL ); 771 } 772 773 Type = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); 774 Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext; 775 776 if (Type < DirectoryFile) { 777 778 if (Header->Resource) { 779 780 ExReleaseResourceLite( Header->Resource ); 781 } 782 } 783 784 if (Header->PagingIoResource) { 785 786 ExReleaseResourceLite( Header->PagingIoResource ); 787 } 788 789 return STATUS_SUCCESS; 790 } 791 792 793 BOOLEAN 794 NTAPI 795 FatNoOpAcquire ( 796 IN PVOID Fcb, 797 IN BOOLEAN Wait 798 ) 799 800 /*++ 801 802 Routine Description: 803 804 This routine does nothing. 805 806 Arguments: 807 808 Fcb - The Fcb/Dcb/Vcb which was specified as a context parameter for this 809 routine. 810 811 Wait - TRUE if the caller is willing to block. 812 813 Return Value: 814 815 TRUE 816 817 --*/ 818 819 { 820 UNREFERENCED_PARAMETER( Fcb ); 821 UNREFERENCED_PARAMETER( Wait ); 822 823 PAGED_CODE(); 824 825 // 826 // This is a kludge because Cc is really the top level. We it 827 // enters the file system, we will think it is a resursive call 828 // and complete the request with hard errors or verify. It will 829 // have to deal with them, somehow.... 830 // 831 832 NT_ASSERT(IoGetTopLevelIrp() == NULL); 833 834 IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 835 836 return TRUE; 837 } 838 839 840 VOID 841 NTAPI 842 FatNoOpRelease ( 843 IN PVOID Fcb 844 ) 845 846 /*++ 847 848 Routine Description: 849 850 This routine does nothing. 851 852 Arguments: 853 854 Fcb - The Fcb/Dcb/Vcb which was specified as a context parameter for this 855 routine. 856 857 Return Value: 858 859 None 860 861 --*/ 862 863 { 864 PAGED_CODE(); 865 866 // 867 // Clear the kludge at this point. 868 // 869 870 NT_ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 871 872 IoSetTopLevelIrp( NULL ); 873 874 UNREFERENCED_PARAMETER( Fcb ); 875 876 return; 877 } 878 879 880 _Requires_lock_held_(_Global_critical_region_) 881 NTSTATUS 882 NTAPI 883 FatFilterCallbackAcquireForCreateSection ( 884 IN PFS_FILTER_CALLBACK_DATA CallbackData, 885 OUT PVOID *CompletionContext 886 ) 887 888 /*++ 889 890 Routine Description: 891 892 This is the callback routine for MM to use to acquire the file exclusively. 893 894 NOTE: This routine expects the default FSRTL routine to be used to release 895 the resource. If this routine is ever changed to acquire something 896 other than main, a corresponding release routine will be required. 897 898 Arguments: 899 900 FS_FILTER_CALLBACK_DATA - Filter based callback data that provides the file object we 901 want to acquire. 902 903 CompletionContext - Ignored. 904 905 Return Value: 906 907 On success we return STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY. 908 909 If SyncType is SyncTypeCreateSection, we return a status that indicates whether there 910 are any writers to this file. Note that main is acquired, so new handles cannot be opened. 911 912 --*/ 913 914 { 915 PFCB Fcb; 916 917 PAGED_CODE(); 918 919 NT_ASSERT( CallbackData->Operation == FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION ); 920 NT_ASSERT( CallbackData->SizeOfFsFilterCallbackData == sizeof(FS_FILTER_CALLBACK_DATA) ); 921 922 // 923 // Grab the Fcb from the callback data file object. 924 // 925 926 Fcb = CallbackData->FileObject->FsContext; 927 928 // 929 // Take main exclusive. 930 // 931 932 // 933 // Note that we do not need to disable APC delivery to guard 934 // against a rogue user issuing a suspend APC. That is because 935 // it is guaranteed that the caller is either in the system context, 936 // to which a user cannot deliver a suspend APC, or the caller has 937 // already disabled kernel APC delivery before calling. This is true 938 // for all the other pre-acquire routines as well. 939 // 940 941 if (Fcb->Header.Resource) { 942 943 ExAcquireResourceExclusiveLite( Fcb->Header.Resource, TRUE ); 944 } 945 946 // 947 // Return the appropriate status based on the type of synchronization and whether anyone 948 // has write access to this file. 949 // 950 951 if (CallbackData->Parameters.AcquireForSectionSynchronization.SyncType != SyncTypeCreateSection) { 952 953 return STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY; 954 955 } else if (Fcb->ShareAccess.Writers == 0) { 956 957 return STATUS_FILE_LOCKED_WITH_ONLY_READERS; 958 959 } else { 960 961 return STATUS_FILE_LOCKED_WITH_WRITERS; 962 } 963 964 UNREFERENCED_PARAMETER( CompletionContext ); 965 } 966 967