1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 Close.c 8 9 Abstract: 10 11 This module implements the File Close routine for Cdfs called by the 12 Fsd/Fsp dispatch routines. 13 14 The close operation interacts with both the async and delayed close queues 15 in the CdData structure. Since close may be called recursively we may 16 violate the locking order in acquiring the Vcb or Fcb. In this case 17 we may move the request to the async close queue. If this is the last 18 reference on the Fcb and there is a chance the user may reopen this 19 file again soon we would like to defer the close. In this case we 20 may move the request to the async close queue. 21 22 Once we are past the decode file operation there is no need for the 23 file object. If we are moving the request to either of the work 24 queues then we remember all of the information from the file object and 25 complete the request with STATUS_SUCCESS. The Io system can then 26 reuse the file object and we can complete the request when convenient. 27 28 The async close queue consists of requests which we would like to 29 complete as soon as possible. They are queued using the original 30 IrpContext where some of the fields have been overwritten with 31 information from the file object. We will extract this information, 32 cleanup the IrpContext and then call the close worker routine. 33 34 The delayed close queue consists of requests which we would like to 35 defer the close for. We keep size of this list within a range 36 determined by the size of the system. We let it grow to some maximum 37 value and then shrink to some minimum value. We allocate a small 38 structure which contains the key information from the file object 39 and use this information along with an IrpContext on the stack 40 to complete the request. 41 42 43 --*/ 44 45 #include "cdprocs.h" 46 47 // 48 // The Bug check file id for this module 49 // 50 51 #define BugCheckFileId (CDFS_BUG_CHECK_CLOSE) 52 53 // 54 // Local support routines 55 // 56 57 _Requires_lock_held_(_Global_critical_region_) 58 BOOLEAN 59 CdCommonClosePrivate ( 60 _In_ PIRP_CONTEXT IrpContext, 61 _In_ PVCB Vcb, 62 _In_ PFCB Fcb, 63 _In_ ULONG UserReference, 64 _In_ BOOLEAN FromFsd 65 ); 66 67 VOID 68 CdQueueClose ( 69 _In_ PIRP_CONTEXT IrpContext, 70 _In_ PFCB Fcb, 71 _In_ ULONG UserReference, 72 _In_ BOOLEAN DelayedClose 73 ); 74 75 PIRP_CONTEXT 76 CdRemoveClose ( 77 _In_opt_ PVCB Vcb 78 ); 79 80 // Tell prefast this is a workitem routine 81 IO_WORKITEM_ROUTINE CdCloseWorker; 82 83 VOID 84 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 85 CdCloseWorker ( 86 _In_ PDEVICE_OBJECT DeviceObject, 87 _In_opt_ PVOID Context 88 ); 89 90 #ifdef ALLOC_PRAGMA 91 #pragma alloc_text(PAGE, CdFspClose) 92 #pragma alloc_text(PAGE, CdCommonClose) 93 #pragma alloc_text(PAGE, CdCommonClosePrivate) 94 #pragma alloc_text(PAGE, CdQueueClose) 95 #pragma alloc_text(PAGE, CdRemoveClose) 96 #pragma alloc_text(PAGE, CdCloseWorker) 97 #endif 98 99 100 VOID 101 CdFspClose ( 102 _In_opt_ PVCB Vcb 103 ) 104 105 /*++ 106 107 Routine Description: 108 109 This routine is called to process the close queues in the CdData. If the 110 Vcb is passed then we want to remove all of the closes for this Vcb. 111 Otherwise we will do as many of the delayed closes as we need to do. 112 113 Arguments: 114 115 Vcb - If specified then we are looking for all of the closes for the 116 given Vcb. 117 118 Return Value: 119 120 None 121 122 --*/ 123 124 { 125 PIRP_CONTEXT IrpContext; 126 IRP_CONTEXT StackIrpContext; 127 128 THREAD_CONTEXT ThreadContext = {0}; 129 130 PFCB Fcb; 131 ULONG UserReference; 132 133 ULONG VcbHoldCount = 0; 134 PVCB CurrentVcb = NULL; 135 136 BOOLEAN PotentialVcbTeardown = FALSE; 137 138 PAGED_CODE(); 139 140 FsRtlEnterFileSystem(); 141 142 // 143 // Continue processing until there are no more closes to process. 144 // 145 146 while ((IrpContext = CdRemoveClose( Vcb )) != NULL) { 147 148 // 149 // If we don't have an IrpContext then use the one on the stack. 150 // Initialize it for this request. 151 // 152 153 if (SafeNodeType( IrpContext ) != CDFS_NTC_IRP_CONTEXT ) { 154 155 // 156 // Update the local values from the IrpContextLite. 157 // 158 159 Fcb = ((PIRP_CONTEXT_LITE) IrpContext)->Fcb; 160 UserReference = ((PIRP_CONTEXT_LITE) IrpContext)->UserReference; 161 162 // 163 // Update the stack irp context with the values from the 164 // IrpContextLite. 165 // 166 167 CdInitializeStackIrpContext( &StackIrpContext, 168 (PIRP_CONTEXT_LITE) IrpContext ); 169 170 // 171 // Free the IrpContextLite. 172 // 173 174 CdFreeIrpContextLite( *(PVOID*)&IrpContext ); /* ReactOS Change: GCC "error: invalid lvalue in unary '&'" */ 175 176 // 177 // Remember we have the IrpContext from the stack. 178 // 179 180 IrpContext = &StackIrpContext; 181 182 // 183 // Otherwise cleanup the existing IrpContext. 184 // 185 186 } else { 187 188 // 189 // Remember the Fcb and user reference count. 190 // 191 192 Fcb = (PFCB) IrpContext->Irp; 193 IrpContext->Irp = NULL; 194 195 UserReference = (ULONG) IrpContext->ExceptionStatus; 196 IrpContext->ExceptionStatus = STATUS_SUCCESS; 197 } 198 199 _Analysis_assume_(Fcb != NULL && Fcb->Vcb != NULL); 200 201 // 202 // We have an IrpContext. Now we need to set the top level thread 203 // context. 204 // 205 206 SetFlag( IrpContext->Flags, IRP_CONTEXT_FSP_FLAGS ); 207 208 // 209 // If we were given a Vcb then there is a request on top of this. 210 // 211 212 if (ARGUMENT_PRESENT( Vcb )) { 213 214 ClearFlag( IrpContext->Flags, 215 IRP_CONTEXT_FLAG_TOP_LEVEL | IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS ); 216 } 217 218 CdSetThreadContext( IrpContext, &ThreadContext ); 219 220 // 221 // If we have hit the maximum number of requests to process without 222 // releasing the Vcb then release the Vcb now. If we are holding 223 // a different Vcb to this one then release the previous Vcb. 224 // 225 // In either case acquire the current Vcb. 226 // 227 // We use the MinDelayedCloseCount from the CdData since it is 228 // a convenient value based on the system size. Only thing we are trying 229 // to do here is prevent this routine starving other threads which 230 // may need this Vcb exclusively. 231 // 232 // Note that the check for potential teardown below is unsafe. We'll 233 // repeat later within the cddata lock. 234 // 235 236 PotentialVcbTeardown = !ARGUMENT_PRESENT( Vcb ) && 237 (Fcb->Vcb->VcbCondition != VcbMounted) && 238 (Fcb->Vcb->VcbCondition != VcbMountInProgress) && 239 (Fcb->Vcb->VcbCleanup == 0); 240 241 if (PotentialVcbTeardown || 242 (VcbHoldCount > CdData.MinDelayedCloseCount) || 243 (Fcb->Vcb != CurrentVcb)) { 244 245 if (CurrentVcb != NULL) { 246 247 CdReleaseVcb( IrpContext, CurrentVcb ); 248 } 249 250 if (PotentialVcbTeardown) { 251 252 CdAcquireCdData( IrpContext ); 253 254 // 255 // Repeat the checks with global lock held. The volume could have 256 // been remounted while we didn't hold the lock. 257 // 258 259 PotentialVcbTeardown = !ARGUMENT_PRESENT( Vcb ) && 260 (Fcb->Vcb->VcbCondition != VcbMounted) && 261 (Fcb->Vcb->VcbCondition != VcbMountInProgress) && 262 (Fcb->Vcb->VcbCleanup == 0); 263 264 if (!PotentialVcbTeardown) { 265 266 CdReleaseCdData( IrpContext); 267 } 268 } 269 270 CurrentVcb = Fcb->Vcb; 271 272 _Analysis_assume_( CurrentVcb != NULL ); 273 274 CdAcquireVcbShared( IrpContext, CurrentVcb, FALSE ); 275 276 VcbHoldCount = 0; 277 278 } else { 279 280 VcbHoldCount += 1; 281 } 282 283 // 284 // Call our worker routine to perform the close operation. 285 // 286 287 CdCommonClosePrivate( IrpContext, CurrentVcb, Fcb, UserReference, FALSE ); 288 289 // 290 // If the reference count on this Vcb is below our residual reference 291 // then check if we should dismount the volume. 292 // 293 294 if (PotentialVcbTeardown) { 295 296 CdReleaseVcb( IrpContext, CurrentVcb ); 297 CdCheckForDismount( IrpContext, CurrentVcb, FALSE ); 298 299 CurrentVcb = NULL; 300 301 CdReleaseCdData( IrpContext ); 302 PotentialVcbTeardown = FALSE; 303 } 304 305 // 306 // Complete the current request to cleanup the IrpContext. 307 // 308 309 CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS ); 310 } 311 312 // 313 // Release any Vcb we may still hold. 314 // 315 316 if (CurrentVcb != NULL) { 317 318 CdReleaseVcb( IrpContext, CurrentVcb ); 319 320 } 321 322 #ifdef _MSC_VER 323 #pragma prefast(suppress:26165, "Esp:1153") 324 #endif 325 FsRtlExitFileSystem(); 326 } 327 328 _Requires_lock_held_(_Global_critical_region_) 329 NTSTATUS 330 CdCommonClose ( 331 _Inout_ PIRP_CONTEXT IrpContext, 332 _Inout_ PIRP Irp 333 ) 334 335 /*++ 336 337 Routine Description: 338 339 This routine is the Fsd entry for the close operation. We decode the file 340 object to find the CDFS structures and type of open. We call our internal 341 worker routine to perform the actual work. If the work wasn't completed 342 then we post to one of our worker queues. The Ccb isn't needed after this 343 point so we delete the Ccb and return STATUS_SUCCESS to our caller in all 344 cases. 345 346 Arguments: 347 348 Irp - Supplies the Irp to process 349 350 Return Value: 351 352 STATUS_SUCCESS 353 354 --*/ 355 356 { 357 TYPE_OF_OPEN TypeOfOpen; 358 359 PVCB Vcb; 360 PFCB Fcb; 361 PCCB Ccb; 362 ULONG UserReference = 0; 363 364 BOOLEAN PotentialVcbTeardown = FALSE; 365 366 PAGED_CODE(); 367 368 ASSERT_IRP_CONTEXT( IrpContext ); 369 ASSERT_IRP( Irp ); 370 371 // 372 // If we were called with our file system device object instead of a 373 // volume device object, just complete this request with STATUS_SUCCESS. 374 // 375 376 if (IrpContext->Vcb == NULL) { 377 378 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 379 return STATUS_SUCCESS; 380 } 381 382 // 383 // Decode the file object to get the type of open and Fcb/Ccb. 384 // 385 386 TypeOfOpen = CdDecodeFileObject( IrpContext, 387 IoGetCurrentIrpStackLocation( Irp )->FileObject, 388 &Fcb, 389 &Ccb ); 390 391 // 392 // No work to do for unopened file objects. 393 // 394 395 if (TypeOfOpen == UnopenedFileObject) { 396 397 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 398 399 return STATUS_SUCCESS; 400 } 401 402 Vcb = Fcb->Vcb; 403 404 // 405 // Clean up any CCB associated with this open. 406 // 407 408 if (Ccb != NULL) { 409 410 UserReference = 1; 411 412 // 413 // We can always deallocate the Ccb if present. 414 // 415 416 CdDeleteCcb( IrpContext, Ccb ); 417 } 418 419 // 420 // If this is the last reference to a user file or directory on a 421 // currently mounted volume, then post it to the delayed close queue. Note 422 // that the VcbCondition check is unsafe, but it doesn't really matter - 423 // we just might delay the volume teardown a little by posting this close. 424 // 425 426 if ((Vcb->VcbCondition == VcbMounted) && 427 (Fcb->FcbReference == 1) && 428 ((TypeOfOpen == UserFileOpen) || 429 (TypeOfOpen == UserDirectoryOpen))) { 430 431 CdQueueClose( IrpContext, Fcb, UserReference, TRUE ); 432 IrpContext = NULL; 433 434 // 435 // Otherwise try to process this close. Post to the async close queue 436 // if we can't acquire all of the resources. 437 // 438 439 } 440 else { 441 442 // 443 // If we may be dismounting this volume then acquire the CdData 444 // resource. 445 // 446 // Since we now must make volumes go away as soon as reasonable after 447 // the last user handles closes, key off of the cleanup count. It is 448 // OK to do this more than neccesary. Since this Fcb could be holding 449 // a number of other Fcbs (and thus their references), a simple check 450 // on reference count is not appropriate. 451 // 452 // Do an unsafe check first to avoid taking the (global) cddata lock in the 453 // common case. 454 // 455 456 if ((Vcb->VcbCleanup == 0) && 457 (Vcb->VcbCondition != VcbMounted)) { 458 459 // 460 // Possible dismount. Acquire CdData to synchronise with the remount path 461 // before looking at the vcb condition again. 462 // 463 464 CdAcquireCdData( IrpContext ); 465 466 if ((Vcb->VcbCleanup == 0) && 467 (Vcb->VcbCondition != VcbMounted) && 468 (Vcb->VcbCondition != VcbMountInProgress) && 469 FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS )) { 470 471 PotentialVcbTeardown = TRUE; 472 } 473 else { 474 475 // 476 // We can't dismount this volume now, there are other references or 477 // it's just been remounted. 478 // 479 } 480 481 // 482 // Drop the global lock if we don't need it anymore. 483 // 484 485 if (!PotentialVcbTeardown) { 486 487 CdReleaseCdData( IrpContext ); 488 } 489 } 490 491 // 492 // Call the worker routine to perform the actual work. This routine 493 // should never raise except for a fatal error. 494 // 495 496 if (!CdCommonClosePrivate( IrpContext, Vcb, Fcb, UserReference, TRUE )) { 497 498 // 499 // If we didn't complete the request then post the request as needed. 500 // 501 502 CdQueueClose( IrpContext, Fcb, UserReference, FALSE ); 503 IrpContext = NULL; 504 505 // 506 // Check whether we should be dismounting the volume and then complete 507 // the request. 508 // 509 510 } 511 else if (PotentialVcbTeardown) { 512 513 CdCheckForDismount( IrpContext, Vcb, FALSE ); 514 } 515 } 516 517 // 518 // Always complete this request with STATUS_SUCCESS. 519 // 520 521 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); 522 523 if (PotentialVcbTeardown) { 524 525 CdReleaseCdData( IrpContext ); 526 } 527 528 // 529 // Always return STATUS_SUCCESS for closes. 530 // 531 532 return STATUS_SUCCESS; 533 } 534 535 536 // 537 // Local support routine 538 // 539 540 _Requires_lock_held_(_Global_critical_region_) 541 BOOLEAN 542 CdCommonClosePrivate ( 543 _In_ PIRP_CONTEXT IrpContext, 544 _In_ PVCB Vcb, 545 _In_ PFCB Fcb, 546 _In_ ULONG UserReference, 547 _In_ BOOLEAN FromFsd 548 ) 549 550 /*++ 551 552 Routine Description: 553 554 This is the worker routine for the close operation. We can be called in 555 an Fsd thread or from a worker Fsp thread. If called from the Fsd thread 556 then we acquire the resources without waiting. Otherwise we know it is 557 safe to wait. 558 559 We check to see whether we should post this request to the delayed close 560 queue. If we are to process the close here then we acquire the Vcb and 561 Fcb. We will adjust the counts and call our teardown routine to see 562 if any of the structures should go away. 563 564 Arguments: 565 566 Vcb - Vcb for this volume. 567 568 Fcb - Fcb for this request. 569 570 UserReference - Number of user references for this file object. This is 571 zero for an internal stream. 572 573 FromFsd - This request was called from an Fsd thread. Indicates whether 574 we should wait to acquire resources. 575 576 DelayedClose - Address to store whether we should try to put this on 577 the delayed close queue. Ignored if this routine can process this 578 close. 579 580 Return Value: 581 582 BOOLEAN - TRUE if this thread processed the close, FALSE otherwise. 583 584 --*/ 585 586 { 587 BOOLEAN RemovedFcb; 588 589 PAGED_CODE(); 590 591 ASSERT_IRP_CONTEXT( IrpContext ); 592 ASSERT_FCB( Fcb ); 593 594 // 595 // Try to acquire the Vcb and Fcb. If we can't acquire them then return 596 // and let our caller know he should post the request to the async 597 // queue. 598 // 599 600 if (CdAcquireVcbShared( IrpContext, Vcb, FromFsd )) { 601 602 if (!CdAcquireFcbExclusive( IrpContext, Fcb, FromFsd )) { 603 604 // 605 // We couldn't get the Fcb. Release the Vcb and let our caller 606 // know to post this request. 607 // 608 609 CdReleaseVcb( IrpContext, Vcb ); 610 return FALSE; 611 } 612 613 // 614 // We didn't get the Vcb. Let our caller know to post this request. 615 // 616 617 } else { 618 619 return FALSE; 620 } 621 622 // 623 // Lock the Vcb and decrement the reference counts. 624 // 625 626 CdLockVcb( IrpContext, Vcb ); 627 CdDecrementReferenceCounts( IrpContext, Fcb, 1, UserReference ); 628 CdUnlockVcb( IrpContext, Vcb ); 629 630 // 631 // Call our teardown routine to see if this object can go away. 632 // If we don't remove the Fcb then release it. 633 // 634 635 CdTeardownStructures( IrpContext, Fcb, &RemovedFcb ); 636 637 if (!RemovedFcb) { 638 639 CdReleaseFcb( IrpContext, Fcb ); 640 } 641 else { 642 _Analysis_assume_lock_not_held_(Fcb->FcbNonpaged->FcbResource); 643 } 644 645 // 646 // Release the Vcb and return to our caller. Let him know we completed 647 // this request. 648 // 649 650 CdReleaseVcb( IrpContext, Vcb ); 651 652 return TRUE; 653 } 654 655 VOID 656 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 657 CdCloseWorker ( 658 _In_ PDEVICE_OBJECT DeviceObject, 659 _In_opt_ PVOID Context 660 ) 661 /*++ 662 663 Routine Description: 664 665 Worker routine to call CsFspClose. 666 667 Arguments: 668 669 DeviceObject - Filesystem registration device object 670 671 Context - Callers context 672 673 Return Value: 674 675 None 676 677 --*/ 678 679 { 680 PAGED_CODE(); 681 682 UNREFERENCED_PARAMETER( DeviceObject ); 683 UNREFERENCED_PARAMETER( Context ); 684 685 CdFspClose (NULL); 686 } 687 688 689 VOID 690 CdQueueClose ( 691 _In_ PIRP_CONTEXT IrpContext, 692 _In_ PFCB Fcb, 693 _In_ ULONG UserReference, 694 _In_ BOOLEAN DelayedClose 695 ) 696 697 /*++ 698 699 Routine Description: 700 701 This routine is called to queue a request to either the async or delayed 702 close queue. For the delayed queue we need to allocate a smaller 703 structure to contain the information about the file object. We do 704 that so we don't put the larger IrpContext structures into this long 705 lived queue. If we can allocate this structure then we put this 706 on the async queue instead. 707 708 Arguments: 709 710 Fcb - Fcb for this file object. 711 712 UserReference - Number of user references for this file object. This is 713 zero for an internal stream. 714 715 DelayedClose - Indicates whether this should go on the async or delayed 716 close queue. 717 718 Return Value: 719 720 None 721 722 --*/ 723 724 { 725 PIRP_CONTEXT_LITE IrpContextLite = NULL; 726 BOOLEAN StartWorker = FALSE; 727 728 PAGED_CODE(); 729 730 ASSERT_IRP_CONTEXT( IrpContext ); 731 ASSERT_FCB( Fcb ); 732 733 // 734 // Start with the delayed queue request. We can move this to the async 735 // queue if there is an allocation failure. 736 // 737 738 if (DelayedClose) { 739 740 // 741 // Try to allocate non-paged pool for the IRP_CONTEXT_LITE. 742 // 743 744 IrpContextLite = CdCreateIrpContextLite( IrpContext ); 745 } 746 747 // 748 // We want to clear the top level context in this thread if 749 // necessary. Call our cleanup routine to do the work. 750 // 751 752 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING ); 753 CdCleanupIrpContext( IrpContext, TRUE ); 754 755 // 756 // Synchronize with the CdData lock. 757 // 758 759 CdLockCdData(); 760 761 // 762 // If we have an IrpContext then put the request on the delayed close queue. 763 // 764 765 if (IrpContextLite != NULL) { 766 767 // 768 // Initialize the IrpContextLite. 769 // 770 771 IrpContextLite->NodeTypeCode = CDFS_NTC_IRP_CONTEXT_LITE; 772 IrpContextLite->NodeByteSize = sizeof( IRP_CONTEXT_LITE ); 773 IrpContextLite->Fcb = Fcb; 774 IrpContextLite->UserReference = UserReference; 775 IrpContextLite->RealDevice = IrpContext->RealDevice; 776 777 // 778 // Add this to the delayed close list and increment 779 // the count. 780 // 781 782 InsertTailList( &CdData.DelayedCloseQueue, 783 &IrpContextLite->DelayedCloseLinks ); 784 785 CdData.DelayedCloseCount += 1; 786 787 // 788 // If we are above our threshold then start the delayed 789 // close operation. 790 // 791 792 if (CdData.DelayedCloseCount > CdData.MaxDelayedCloseCount) { 793 794 CdData.ReduceDelayedClose = TRUE; 795 796 if (!CdData.FspCloseActive) { 797 798 CdData.FspCloseActive = TRUE; 799 StartWorker = TRUE; 800 } 801 } 802 803 // 804 // Unlock the CdData. 805 // 806 807 CdUnlockCdData(); 808 809 // 810 // Cleanup the IrpContext. 811 // 812 813 CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS ); 814 815 // 816 // Otherwise drop into the async case below. 817 // 818 819 } else { 820 821 // 822 // Store the information about the file object into the IrpContext. 823 // 824 825 IrpContext->Irp = (PIRP) Fcb; 826 IrpContext->ExceptionStatus = (NTSTATUS) UserReference; 827 828 // 829 // Add this to the async close list and increment the count. 830 // 831 832 InsertTailList( &CdData.AsyncCloseQueue, 833 &IrpContext->WorkQueueItem.List ); 834 835 CdData.AsyncCloseCount += 1; 836 837 // 838 // Remember to start the Fsp close thread if not currently started. 839 // 840 841 if (!CdData.FspCloseActive) { 842 843 CdData.FspCloseActive = TRUE; 844 845 StartWorker = TRUE; 846 } 847 848 // 849 // Unlock the CdData. 850 // 851 852 CdUnlockCdData(); 853 } 854 855 // 856 // Start the FspClose thread if we need to. 857 // 858 859 if (StartWorker) { 860 861 IoQueueWorkItem( CdData.CloseItem, CdCloseWorker, CriticalWorkQueue, NULL ); 862 } 863 864 // 865 // Return to our caller. 866 // 867 868 return; 869 } 870 871 872 // 873 // Local support routine 874 // 875 876 PIRP_CONTEXT 877 CdRemoveClose ( 878 _In_opt_ PVCB Vcb 879 ) 880 881 /*++ 882 883 Routine Description: 884 885 Arguments: 886 887 This routine is called to scan the async and delayed close queues looking 888 for a suitable entry. If the Vcb is specified then we scan both queues 889 looking for an entry with the same Vcb. Otherwise we will look in the 890 async queue first for any close item. If none found there then we look 891 in the delayed close queue provided that we have triggered the delayed 892 close operation. 893 894 Return Value: 895 896 PIRP_CONTEXT - NULL if no work item found. Otherwise it is the pointer to 897 either the IrpContext or IrpContextLite for this request. 898 899 --*/ 900 901 { 902 PIRP_CONTEXT IrpContext = NULL; 903 PIRP_CONTEXT NextIrpContext; 904 PIRP_CONTEXT_LITE NextIrpContextLite; 905 906 PLIST_ENTRY Entry; 907 908 PAGED_CODE(); 909 910 ASSERT_OPTIONAL_VCB( Vcb ); 911 912 // 913 // Lock the CdData to perform the scan. 914 // 915 916 CdLockCdData(); 917 918 // 919 // First check the list of async closes. 920 // 921 922 Entry = CdData.AsyncCloseQueue.Flink; 923 924 while (Entry != &CdData.AsyncCloseQueue) { 925 926 // 927 // Extract the IrpContext. 928 // 929 930 NextIrpContext = CONTAINING_RECORD( Entry, 931 IRP_CONTEXT, 932 WorkQueueItem.List ); 933 934 // 935 // If no Vcb was specified or this Vcb is for our volume 936 // then perform the close. 937 // 938 939 if (!ARGUMENT_PRESENT( Vcb ) || (NextIrpContext->Vcb == Vcb)) { 940 941 RemoveEntryList( Entry ); 942 CdData.AsyncCloseCount -= 1; 943 944 IrpContext = NextIrpContext; 945 break; 946 } 947 948 // 949 // Move to the next entry. 950 // 951 952 Entry = Entry->Flink; 953 } 954 955 // 956 // If we didn't find anything look through the delayed close 957 // queue. 958 // 959 // We will only check the delayed close queue if we were given 960 // a Vcb or the delayed close operation is active. 961 // 962 963 if ((IrpContext == NULL) && 964 (ARGUMENT_PRESENT( Vcb ) || 965 (CdData.ReduceDelayedClose && 966 (CdData.DelayedCloseCount > CdData.MinDelayedCloseCount)))) { 967 968 Entry = CdData.DelayedCloseQueue.Flink; 969 970 while (Entry != &CdData.DelayedCloseQueue) { 971 972 // 973 // Extract the IrpContext. 974 // 975 976 NextIrpContextLite = CONTAINING_RECORD( Entry, 977 IRP_CONTEXT_LITE, 978 DelayedCloseLinks ); 979 980 // 981 // If no Vcb was specified or this Vcb is for our volume 982 // then perform the close. 983 // 984 985 if (!ARGUMENT_PRESENT( Vcb ) || (NextIrpContextLite->Fcb->Vcb == Vcb)) { 986 987 RemoveEntryList( Entry ); 988 CdData.DelayedCloseCount -= 1; 989 990 IrpContext = (PIRP_CONTEXT) NextIrpContextLite; 991 break; 992 } 993 994 // 995 // Move to the next entry. 996 // 997 998 Entry = Entry->Flink; 999 } 1000 } 1001 1002 // 1003 // If the Vcb wasn't specified and we couldn't find an entry 1004 // then turn off the Fsp thread. 1005 // 1006 1007 if (!ARGUMENT_PRESENT( Vcb ) && (IrpContext == NULL)) { 1008 1009 CdData.FspCloseActive = FALSE; 1010 CdData.ReduceDelayedClose = FALSE; 1011 } 1012 1013 // 1014 // Unlock the CdData. 1015 // 1016 1017 CdUnlockCdData(); 1018 1019 return IrpContext; 1020 } 1021 1022 1023 1024