test: close.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# close.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     Close.c
    00008
    00009 Abstract:
    00010
    00011     This module implements the File Close routine for Udfs called by the
    00012     Fsd/Fsp dispatch routines.
    00013
    00014     The close operation interacts with both the async and delayed close queues
    00015     in the UdfData structure.  Since close may be called recursively we may
    00016     violate the locking order in acquiring the Vcb or Fcb.  In this case
    00017     we may move the request to the async close queue.  If this is the last
    00018     reference on the Fcb and there is a chance the user may reopen this
    00019     file again soon we would like to defer the close.  In this case we
    00020     may move the request to the delayed close queue.
    00021
    00022     Once we are past the decode file operation there is no need for the
    00023     file object.  If we are moving the request to either of the work
    00024     queues then we remember all of the information from the file object and
    00025     complete the request with STATUS_SUCCESS.  The Io system can then
    00026     reuse the file object and we can complete the request when convenient.
    00027
    00028     The async close queue consists of requests which we would like to
    00029     complete as soon as possible.  They are queued using the original
    00030     IrpContext where some of the fields have been overwritten with
    00031     information from the file object.  We will extract this information,
    00032     cleanup the IrpContext and then call the close worker routine.
    00033
    00034     The delayed close queue consists of requests which we would like to
    00035     defer the close for.  We keep size of this list within a range
    00036     determined by the size of the system.  We let it grow to some maximum
    00037     value and then shrink to some minimum value.  We allocate a small
    00038     structure which contains the key information from the file object
    00039     and use this information along with an IrpContext on the stack
    00040     to complete the request.
    00041
    00042 Author:
    00043
    00044     Dan Lovinger    [DanLo]     04-Nov-1996
    00045
    00046 Revision History:
    00047
    00048 --*/
    00049
    00050 #include "UdfProcs.h"
    00051
    00052 //
    00053 //  The Bug check file id for this module
    00054 //
    00055
    00056 #define BugCheckFileId                   (UDFS_BUG_CHECK_CLOSE)
    00057
    00058 //
    00059 //  The local debug trace level
    00060 //
    00061
    00062 #define Dbg                              (UDFS_DEBUG_LEVEL_CLOSE)
    00063
    00064 //
    00065 //  Local support routines
    00066 //
    00067
    00068 BOOLEAN
    00069 UdfCommonClosePrivate (
    00070     IN PIRP_CONTEXT IrpContext,
    00071     IN PVCB Vcb,
    00072     IN PFCB Fcb,
    00073     IN ULONG UserReference,
    00074     IN BOOLEAN FromFsd
    00075     );
    00076
    00077 VOID
    00078 UdfQueueClose (
    00079     IN PIRP_CONTEXT IrpContext,
    00080     IN PFCB Fcb,
    00081     IN ULONG UserReference,
    00082     IN BOOLEAN DelayedClose
    00083     );
    00084
    00085 PIRP_CONTEXT
    00086 UdfRemoveClose (
    00087     IN PVCB Vcb OPTIONAL
    00088     );
    00089
    00090 #ifdef ALLOC_PRAGMA
    00091 #pragma alloc_text(PAGE, UdfCommonClose)
    00092 #pragma alloc_text(PAGE, UdfCommonClosePrivate)
    00093 #pragma alloc_text(PAGE, UdfQueueClose)
    00094 #pragma alloc_text(PAGE, UdfRemoveClose)
    00095 #endif
    00096
    00097
    00098 VOID
    00099 UdfFspClose (
    00100     IN PVCB Vcb OPTIONAL
    00101     )
    00102
    00103 /*++
    00104
    00105 Routine Description:
    00106
    00107     This routine is called to process the close queues in the UdfData.  If the
    00108     Vcb is passed then we want to remove all of the closes for this Vcb.
    00109     Otherwise we will do as many of the delayed closes as we need to do.
    00110
    00111 Arguments:
    00112
    00113     Vcb - If specified then we are looking for all of the closes for the
    00114         given Vcb.
    00115
    00116 Return Value:
    00117
    00118     None
    00119
    00120 --*/
    00121
    00122 {
    00123     PIRP_CONTEXT IrpContext;
    00124     IRP_CONTEXT StackIrpContext;
    00125
    00126     THREAD_CONTEXT ThreadContext;
    00127
    00128     PFCB Fcb;
    00129     ULONG UserReference;
    00130
    00131     ULONG VcbHoldCount = 0;
    00132     PVCB CurrentVcb = NULL;
    00133
    00134     BOOLEAN ReleaseUdfData = FALSE;
    00135
    00136     PAGED_CODE();
    00137
    00138     //
    00139     //  Check input.
    00140     //
    00141
    00142     ASSERT_OPTIONAL_VCB( Vcb );
    00143
    00144     FsRtlEnterFileSystem();
    00145
    00146     //
    00147     //  Continue processing until there are no more closes to process.
    00148     //
    00149
    00150     while (IrpContext = UdfRemoveClose( Vcb )) {
    00151
    00152         //
    00153         //  If we don't have an IrpContext then use the one on the stack.
    00154         //  Initialize it for this request.
    00155         //
    00156
    00157         if (SafeNodeType( IrpContext ) != UDFS_NTC_IRP_CONTEXT ) {
    00158
    00159             //
    00160             //  Update the local values from the IrpContextLite.
    00161             //
    00162
    00163             Fcb = ((PIRP_CONTEXT_LITE) IrpContext)->Fcb;
    00164             UserReference = ((PIRP_CONTEXT_LITE) IrpContext)->UserReference;
    00165
    00166             //
    00167             //  Update the stack irp context with the values from the
    00168             //  IrpContextLite.
    00169             //
    00170
    00171             UdfInitializeStackIrpContext( &StackIrpContext,
    00172                                           (PIRP_CONTEXT_LITE) IrpContext );
    00173
    00174             //
    00175             //  Free the IrpContextLite.
    00176             //
    00177
    00178             UdfFreeIrpContextLite( (PIRP_CONTEXT_LITE) IrpContext );
    00179
    00180             //
    00181             //  Remember we have the IrpContext from the stack.
    00182             //
    00183
    00184             IrpContext = &StackIrpContext;
    00185
    00186         //
    00187         //  Otherwise cleanup the existing IrpContext.
    00188         //
    00189
    00190         } else {
    00191
    00192             //
    00193             //  Remember the Fcb and user reference count.
    00194             //
    00195
    00196             Fcb = (PFCB) IrpContext->Irp;
    00197             IrpContext->Irp = NULL;
    00198
    00199             UserReference = (ULONG) IrpContext->ExceptionStatus;
    00200             IrpContext->ExceptionStatus = STATUS_SUCCESS;
    00201         }
    00202
    00203         //
    00204         //  We have an IrpContext.  Now we need to set the top level thread
    00205         //  context.
    00206         //
    00207
    00208         SetFlag( IrpContext->Flags, IRP_CONTEXT_FSP_FLAGS );
    00209
    00210         //
    00211         //  If we were given a Vcb then there is a request on top of this.
    00212         //
    00213
    00214         if (ARGUMENT_PRESENT( Vcb )) {
    00215
    00216             ClearFlag( IrpContext->Flags,
    00217                        IRP_CONTEXT_FLAG_TOP_LEVEL | IRP_CONTEXT_FLAG_TOP_LEVEL_UDFS );
    00218         }
    00219
    00220         UdfSetThreadContext( IrpContext, &ThreadContext );
    00221
    00222         //
    00223         //  If we have hit the maximum number of requests to process without
    00224         //  releasing the Vcb then release the Vcb now.  If we are holding
    00225         //  a different Vcb to this one then release the previous Vcb.
    00226         //
    00227         //  In either case acquire the current Vcb.
    00228         //
    00229         //  We use the MinDelayedCloseCount from the UdfData since it is
    00230         //  a convenient value based on the system size.  Only thing we are trying
    00231         //  to do here is prevent this routine starving other threads which
    00232         //  may need this Vcb exclusively.
    00233         //
    00234
    00235         ReleaseUdfData = !ARGUMENT_PRESENT( Vcb ) &&
    00236                          (Fcb->Vcb->VcbCondition != VcbMounted) &&
    00237                          (Fcb->Vcb->VcbCondition != VcbMountInProgress) &&
    00238                          (Fcb->Vcb->VcbCleanup == 0);
    00239
    00240         if (ReleaseUdfData ||
    00241             (VcbHoldCount > UdfData.MinDelayedCloseCount) ||
    00242             (Fcb->Vcb != CurrentVcb)) {
    00243
    00244             if (CurrentVcb != NULL) {
    00245
    00246                 UdfReleaseVcb( IrpContext, CurrentVcb );
    00247             }
    00248
    00249             if (ReleaseUdfData) {
    00250
    00251                 UdfAcquireUdfData( IrpContext );
    00252             }
    00253
    00254             CurrentVcb = Fcb->Vcb;
    00255             UdfAcquireVcbShared( IrpContext, CurrentVcb, FALSE );
    00256
    00257             VcbHoldCount = 0;
    00258
    00259         } else {
    00260
    00261             VcbHoldCount += 1;
    00262         }
    00263
    00264         DebugTrace(( +1, Dbg,
    00265                      "UdfFspClose, Fcb %08x %4s Vcb %d/%d Fcb %d/%d\n",
    00266                      Fcb,
    00267                      ( UserReference? "USER" : "SYS" ),
    00268                      CurrentVcb->VcbReference,
    00269                      CurrentVcb->VcbUserReference,
    00270                      Fcb->FcbReference,
    00271                      Fcb->FcbUserReference ));
    00272
    00273         //
    00274         //  Call our worker routine to perform the close operation.
    00275         //
    00276
    00277         UdfCommonClosePrivate( IrpContext, CurrentVcb, Fcb, UserReference, FALSE );
    00278
    00279         //
    00280         //  If the reference count on this Vcb is below our residual reference
    00281         //  then check if we should dismount the volume.
    00282         //
    00283
    00284         if (ReleaseUdfData) {
    00285
    00286             UdfReleaseVcb( IrpContext, CurrentVcb );
    00287             UdfCheckForDismount( IrpContext, CurrentVcb, FALSE );
    00288
    00289             CurrentVcb = NULL;
    00290
    00291             UdfReleaseUdfData( IrpContext );
    00292             ReleaseUdfData = FALSE;
    00293         }
    00294
    00295         //
    00296         //  Complete the current request to cleanup the IrpContext.
    00297         //
    00298
    00299         UdfCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
    00300
    00301         DebugTrace(( -1, Dbg, "UdfFspClose -> VOID\n" ));
    00302     }
    00303
    00304     //
    00305     //  Release any Vcb we may still hold.
    00306     //
    00307
    00308     if (CurrentVcb != NULL) {
    00309
    00310         UdfReleaseVcb( IrpContext, CurrentVcb );
    00311     }
    00312
    00313     FsRtlExitFileSystem();
    00314     return;
    00315 }
    00316
    00317
    00318 NTSTATUS
    00319 UdfCommonClose (
    00320     IN PIRP_CONTEXT IrpContext,
    00321     IN PIRP Irp
    00322     )
    00323
    00324 /*++
    00325
    00326 Routine Description:
    00327
    00328     This routine is the Fsd entry for the close operation.  We decode the file
    00329     object to find the UDFS structures and type of open.  We call our internal
    00330     worker routine to perform the actual work.  If the work wasn't completed
    00331     then we post to one of our worker queues.  The Ccb isn't needed after this
    00332     point so we delete the Ccb and return STATUS_SUCCESS to our caller in all
    00333     cases.
    00334
    00335 Arguments:
    00336
    00337     Irp - Supplies the Irp to process
    00338
    00339 Return Value:
    00340
    00341     STATUS_SUCCESS
    00342
    00343 --*/
    00344
    00345 {
    00346     TYPE_OF_OPEN TypeOfOpen;
    00347
    00348     PVCB Vcb;
    00349     PFCB Fcb;
    00350     PCCB Ccb;
    00351     ULONG UserReference = 0;
    00352
    00353     BOOLEAN DelayedClose;
    00354     BOOLEAN ReleaseUdfData = FALSE;
    00355
    00356     PAGED_CODE();
    00357
    00358     //
    00359     //  Check input.
    00360     //
    00361
    00362     ASSERT_IRP_CONTEXT( IrpContext );
    00363     ASSERT_IRP( Irp );
    00364
    00365     //
    00366     //  If we were called with our file system device object instead of a
    00367     //  volume device object, just complete this request with STATUS_SUCCESS.
    00368     //
    00369
    00370     if (IrpContext->Vcb == NULL) {
    00371
    00372         UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
    00373         return STATUS_SUCCESS;
    00374     }
    00375
    00376     //
    00377     //  Decode the file object to get the type of open and Fcb/Ccb.
    00378     //
    00379
    00380     TypeOfOpen = UdfDecodeFileObject( IoGetCurrentIrpStackLocation( Irp )->FileObject,
    00381                                       &Fcb,
    00382                                       &Ccb );
    00383
    00384     //
    00385     //  No work to do for unopened file objects.
    00386     //
    00387
    00388     if (TypeOfOpen == UnopenedFileObject) {
    00389
    00390         UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
    00391
    00392         return STATUS_SUCCESS;
    00393     }
    00394
    00395     Vcb = Fcb->Vcb;
    00396
    00397     //
    00398     //  Call the worker routine to perform the actual work.  This routine
    00399     //  should never raise except for a fatal error.
    00400     //
    00401
    00402     if (Ccb != NULL) {
    00403
    00404         UserReference = 1;
    00405
    00406         //
    00407         //  We can always deallocate the Ccb if present.
    00408         //
    00409
    00410         UdfDeleteCcb( IrpContext, Ccb );
    00411     }
    00412
    00413     //
    00414     //  If this is a user file or directory then check if we should post
    00415     //  this to the delayed close queue.  This has to be the last reference
    00416     //  for a user file or directory open.
    00417     //
    00418
    00419     if ((Vcb->VcbCondition == VcbMounted) &&
    00420         (Fcb->FcbReference == 1) &&
    00421         ((TypeOfOpen == UserFileOpen) ||
    00422          (TypeOfOpen == UserDirectoryOpen))) {
    00423
    00424         UdfQueueClose( IrpContext, Fcb, UserReference, TRUE );
    00425         IrpContext = NULL;
    00426
    00427     //
    00428     //  Otherwise try to process this close.  Post to the async close queue
    00429     //  if we can't acquire all of the resources.
    00430     //
    00431
    00432     } else {
    00433
    00434         //
    00435         //  If we may be dismounting this volume then acquire the UdfData
    00436         //  resource.
    00437         //
    00438         //  Since we now must make volumes go away as soon as reasonable after
    00439         //  the last user handles closes, key off of the cleanup count.  It is
    00440         //  OK to do this more than neccesary.  Since this Fcb could be holding
    00441         //  a number of other Fcbs (and thus their references), a simple check
    00442         //  on reference count is not appropriate.
    00443         //
    00444
    00445         if ((Vcb->VcbCleanup == 0) &&
    00446             (Vcb->VcbCondition != VcbMounted) &&
    00447             (Vcb->VcbCondition != VcbMountInProgress) &&
    00448             FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL_UDFS )) {
    00449
    00450             UdfAcquireUdfData( IrpContext );
    00451             ReleaseUdfData = TRUE;
    00452         }
    00453
    00454         if (!UdfCommonClosePrivate( IrpContext, Vcb, Fcb, UserReference, TRUE )) {
    00455
    00456             //
    00457             //  If we didn't complete the request then post the request as needed.
    00458             //
    00459
    00460             UdfQueueClose( IrpContext, Fcb, UserReference, FALSE );
    00461             IrpContext = NULL;
    00462
    00463         //
    00464         //  Check whether we should be dismounting the volume and then complete
    00465         //  the request.
    00466         //
    00467
    00468         } else if (ReleaseUdfData) {
    00469
    00470             UdfCheckForDismount( IrpContext, Vcb, FALSE );
    00471         }
    00472     }
    00473
    00474     //
    00475     //  Always complete this request with STATUS_SUCCESS.
    00476     //
    00477
    00478     UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
    00479
    00480     if (ReleaseUdfData) {
    00481
    00482         UdfReleaseUdfData( IrpContext );
    00483     }
    00484
    00485     //
    00486     //  Always return STATUS_SUCCESS for closes.
    00487     //
    00488
    00489     return STATUS_SUCCESS;
    00490 }
    00491
    00492
    00493 //
    00494 //  Local support routine
    00495 //
    00496
    00497 BOOLEAN
    00498 UdfCommonClosePrivate (
    00499     IN PIRP_CONTEXT IrpContext,
    00500     IN PVCB Vcb,
    00501     IN PFCB Fcb,
    00502     IN ULONG UserReference,
    00503     IN BOOLEAN FromFsd
    00504     )
    00505
    00506 /*++
    00507
    00508 Routine Description:
    00509
    00510     This is the worker routine for the close operation.  We can be called in
    00511     an Fsd thread or from a worker Fsp thread.  If called from the Fsd thread
    00512     then we acquire the resources without waiting.  Otherwise we know it is
    00513     safe to wait.
    00514
    00515     We check to see whether we should post this request to the delayed close
    00516     queue.  If we are to process the close here then we acquire the Vcb and
    00517     Fcb.  We will adjust the counts and call our teardown routine to see
    00518     if any of the structures should go away.
    00519
    00520 Arguments:
    00521
    00522     Vcb - Vcb for this volume.
    00523
    00524     Fcb - Fcb for this request.
    00525
    00526     UserReference - Number of user references for this file object.  This is
    00527         zero for an internal stream.
    00528
    00529     FromFsd - This request was called from an Fsd thread.  Indicates whether
    00530         we should wait to acquire resources.
    00531
    00532 Return Value:
    00533
    00534     BOOLEAN - TRUE if this thread processed the close, FALSE otherwise.
    00535
    00536 --*/
    00537
    00538 {
    00539     BOOLEAN CompletedClose;
    00540     BOOLEAN RemovedFcb;
    00541
    00542     PAGED_CODE();
    00543
    00544     //
    00545     //  Check inputs.
    00546     //
    00547
    00548     ASSERT_IRP_CONTEXT( IrpContext );
    00549     ASSERT_VCB( Vcb );
    00550     ASSERT_FCB( Fcb );
    00551
    00552     //
    00553     //  Try to acquire the Vcb and Fcb.  If we can't acquire them then return
    00554     //  and let our caller know he should post the request to the async
    00555     //  queue.
    00556     //
    00557
    00558     if (UdfAcquireVcbShared( IrpContext, Vcb, FromFsd )) {
    00559
    00560         if (!UdfAcquireFcbExclusive( IrpContext, Fcb, FromFsd )) {
    00561
    00562             //
    00563             //  We couldn't get the Fcb.  Release the Vcb and let our caller
    00564             //  know to post this request.
    00565             //
    00566
    00567             UdfReleaseVcb( IrpContext, Vcb );
    00568             return FALSE;
    00569         }
    00570
    00571     //
    00572     //  We didn't get the Vcb.  Let our caller know to post this request.
    00573     //
    00574
    00575     } else {
    00576
    00577         return FALSE;
    00578     }
    00579
    00580     //
    00581     //  Lock the Vcb and decrement the reference counts.
    00582     //
    00583
    00584     UdfLockVcb( IrpContext, Vcb );
    00585
    00586     DebugTrace(( +1, Dbg,
    00587                  "UdfCommonClosePrivate, Fcb %08x %4s Vcb %d/%d Fcb %d/%d\n", Fcb,
    00588                  ( UserReference? "USER" : "SYS" ),
    00589                  Vcb->VcbReference,
    00590                  Vcb->VcbUserReference,
    00591                  Fcb->FcbReference,
    00592                  Fcb->FcbUserReference ));
    00593
    00594     UdfDecrementReferenceCounts( IrpContext, Fcb, 1, UserReference );
    00595
    00596     DebugTrace(( +0, Dbg,
    00597                  "UdfCommonClosePrivate, Vcb %d/%d Fcb %d/%d\n",
    00598                  Vcb->VcbReference,
    00599                  Vcb->VcbUserReference,
    00600                  Fcb->FcbReference,
    00601                  Fcb->FcbUserReference ));
    00602
    00603     UdfUnlockVcb( IrpContext, Vcb );
    00604
    00605     //
    00606     //  Call our teardown routine to see if this object can go away.
    00607     //  If we don't remove the Fcb then release it.
    00608     //
    00609
    00610     UdfTeardownStructures( IrpContext, Fcb, FALSE, &RemovedFcb );
    00611
    00612     if (!RemovedFcb) {
    00613
    00614         UdfReleaseFcb( IrpContext, Fcb );
    00615     }
    00616
    00617     DebugTrace(( -1, Dbg,
    00618                  "UdfCommonClosePrivate, RemovedFcb %08x -> %c\n",
    00619                  Fcb,
    00620                  ( RemovedFcb? 'T' : 'F' )));
    00621
    00622     //
    00623     //  Release the Vcb and return to our caller.  Let him know we completed
    00624     //  this request.
    00625     //
    00626
    00627     UdfReleaseVcb( IrpContext, Vcb );
    00628
    00629     return TRUE;
    00630 }
    00631
    00632
    00633 VOID
    00634 UdfQueueClose (
    00635     IN PIRP_CONTEXT IrpContext,
    00636     IN PFCB Fcb,
    00637     IN ULONG UserReference,
    00638     IN BOOLEAN DelayedClose
    00639     )
    00640
    00641 /*++
    00642
    00643 Routine Description:
    00644
    00645     This routine is called to queue a request to either the async or delayed
    00646     close queue.  For the delayed queue we need to allocate a smaller
    00647     structure to contain the information about the file object.  We do
    00648     that so we don't put the larger IrpContext structures into this long
    00649     lived queue.  If we can allocate this structure then we put this
    00650     on the async queue instead.
    00651
    00652 Arguments:
    00653
    00654     Fcb - Fcb for this file object.
    00655
    00656     UserReference - Number of user references for this file object.  This is
    00657         zero for an internal stream.
    00658
    00659     DelayedClose - Indicates whether this should go on the async or delayed
    00660         close queue.
    00661
    00662 Return Value:
    00663
    00664     None
    00665
    00666 --*/
    00667
    00668 {
    00669     PIRP_CONTEXT_LITE IrpContextLite = NULL;
    00670     BOOLEAN StartWorker = FALSE;
    00671
    00672     PAGED_CODE();
    00673
    00674     //
    00675     //  Check inputs.
    00676     //
    00677
    00678     ASSERT_IRP_CONTEXT( IrpContext );
    00679     ASSERT_FCB( Fcb );
    00680
    00681     //
    00682     //  Start with the delayed queue request.  We can move this to the async
    00683     //  queue if there is an allocation failure.
    00684     //
    00685
    00686     if (DelayedClose) {
    00687
    00688         //
    00689         //  Try to allocate non-paged pool for the IRP_CONTEXT_LITE.
    00690         //
    00691
    00692         IrpContextLite = UdfCreateIrpContextLite( IrpContext );
    00693     }
    00694
    00695     //
    00696     //  We want to clear the top level context in this thread if
    00697     //  necessary.  Call our cleanup routine to do the work.
    00698     //
    00699
    00700     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
    00701     UdfCleanupIrpContext( IrpContext, TRUE );
    00702
    00703     //
    00704     //  Synchronize with the UdfData lock.
    00705     //
    00706
    00707     UdfLockUdfData();
    00708
    00709     DebugTrace(( +1, Dbg,
    00710                  "UdfQueueClose, Fcb %08x %4s %5s\n",
    00711                  Fcb,
    00712                  ( UserReference? "USER" : "SYS" ),
    00713                  ( IrpContextLite? "DELAY" : "ASYNC" )));
    00714
    00715
    00716     //
    00717     //  If we have an IrpContext then put the request on the delayed close queue.
    00718     //
    00719
    00720     if (IrpContextLite != NULL) {
    00721
    00722         //
    00723         //  Initialize the IrpContextLite.
    00724         //
    00725
    00726         IrpContextLite->NodeTypeCode = UDFS_NTC_IRP_CONTEXT_LITE;
    00727         IrpContextLite->NodeByteSize = sizeof( IRP_CONTEXT_LITE );
    00728         IrpContextLite->Fcb = Fcb;
    00729         IrpContextLite->UserReference = UserReference;
    00730         IrpContextLite->RealDevice = IrpContext->RealDevice;
    00731
    00732         //
    00733         //  Add this to the delayed close list and increment
    00734         //  the count.
    00735         //
    00736
    00737         InsertTailList( &UdfData.DelayedCloseQueue,
    00738                         &IrpContextLite->DelayedCloseLinks );
    00739
    00740         UdfData.DelayedCloseCount += 1;
    00741
    00742         //
    00743         //  If we are above our threshold then start the delayed
    00744         //  close operation.
    00745         //
    00746
    00747         if (UdfData.DelayedCloseCount > UdfData.MaxDelayedCloseCount) {
    00748
    00749             UdfData.ReduceDelayedClose = TRUE;
    00750
    00751             if (!UdfData.FspCloseActive) {
    00752
    00753                 UdfData.FspCloseActive = TRUE;
    00754                 StartWorker = TRUE;
    00755             }
    00756         }
    00757
    00758         //
    00759         //  Unlock the global data.
    00760         //
    00761
    00762         UdfUnlockUdfData();
    00763
    00764         //
    00765         //  Cleanup the IrpContext.
    00766         //
    00767
    00768         UdfCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
    00769
    00770     //
    00771     //  Otherwise drop into the async case below.
    00772     //
    00773
    00774     } else {
    00775
    00776         //
    00777         //  Store the information about the file object into the IrpContext.
    00778         //
    00779
    00780         IrpContext->Irp = (PIRP) Fcb;
    00781         IrpContext->ExceptionStatus = (NTSTATUS) UserReference;
    00782
    00783         //
    00784         //  Add this to the async close list and increment the count.
    00785         //
    00786
    00787         InsertTailList( &UdfData.AsyncCloseQueue,
    00788                         &IrpContext->WorkQueueItem.List );
    00789
    00790         UdfData.AsyncCloseCount += 1;
    00791
    00792         //
    00793         //  Remember to start the Fsp close thread if not currently started.
    00794         //
    00795
    00796         if (!UdfData.FspCloseActive) {
    00797
    00798             UdfData.FspCloseActive = TRUE;
    00799             StartWorker = TRUE;
    00800         }
    00801
    00802         //
    00803         //  Unlock the global data.
    00804         //
    00805
    00806         UdfUnlockUdfData();
    00807     }
    00808
    00809     //
    00810     //  Start the FspClose thread if we need to.
    00811     //
    00812
    00813     if (StartWorker) {
    00814
    00815         ExQueueWorkItem( &UdfData.CloseItem, CriticalWorkQueue );
    00816     }
    00817
    00818     DebugTrace(( -1, Dbg, "UdfQueueClose -> VOID\n" ));
    00819
    00820     //
    00821     //  Return to our caller.
    00822     //
    00823
    00824     return;
    00825 }
    00826
    00827
    00828 //
    00829 //  Local support routine
    00830 //
    00831
    00832 PIRP_CONTEXT
    00833 UdfRemoveClose (
    00834     IN PVCB Vcb OPTIONAL
    00835     )
    00836
    00837 /*++
    00838
    00839 Routine Description:
    00840
    00841 Arguments:
    00842
    00843     This routine is called to scan the async and delayed close queues looking
    00844     for a suitable entry.  If the Vcb is specified then we scan both queues
    00845     looking for an entry with the same Vcb.  Otherwise we will look in the
    00846     async queue first for any close item.  If none found there then we look
    00847     in the delayed close queue provided that we have triggered the delayed
    00848     close operation.
    00849
    00850 Return Value:
    00851
    00852     PIRP_CONTEXT - NULL if no work item found.  Otherwise it is the pointer to
    00853         either the IrpContext or IrpContextLite for this request.
    00854
    00855 --*/
    00856
    00857 {
    00858     PIRP_CONTEXT IrpContext = NULL;
    00859     PIRP_CONTEXT NextIrpContext;
    00860     PIRP_CONTEXT_LITE NextIrpContextLite;
    00861
    00862     PLIST_ENTRY Entry;
    00863
    00864     PAGED_CODE();
    00865
    00866     ASSERT_OPTIONAL_VCB( Vcb );
    00867
    00868     //
    00869     //  Lock the UdfData to perform the scan.
    00870     //
    00871
    00872     UdfLockUdfData();
    00873
    00874     //
    00875     //  First check the list of async closes.
    00876     //
    00877
    00878     Entry = UdfData.AsyncCloseQueue.Flink;
    00879
    00880     while (Entry != &UdfData.AsyncCloseQueue) {
    00881
    00882         //
    00883         //  Extract the IrpContext.
    00884         //
    00885
    00886         NextIrpContext = CONTAINING_RECORD( Entry,
    00887                                             IRP_CONTEXT,
    00888                                             WorkQueueItem.List );
    00889
    00890         //
    00891         //  If no Vcb was specified or this Vcb is for our volume
    00892         //  then perform the close.
    00893         //
    00894
    00895         if (!ARGUMENT_PRESENT( Vcb ) || (NextIrpContext->Vcb == Vcb)) {
    00896
    00897             RemoveEntryList( Entry );
    00898             UdfData.AsyncCloseCount -= 1;
    00899
    00900             IrpContext = NextIrpContext;
    00901             break;
    00902         }
    00903
    00904         //
    00905         //  Move to the next entry.
    00906         //
    00907
    00908         Entry = Entry->Flink;
    00909     }
    00910
    00911     //
    00912     //  If we didn't find anything look through the delayed close
    00913     //  queue.
    00914     //
    00915     //  We will only check the delayed close queue if we were given
    00916     //  a Vcb or the delayed close operation is active.
    00917     //
    00918
    00919     if ((IrpContext == NULL) &&
    00920         (ARGUMENT_PRESENT( Vcb ) ||
    00921          (UdfData.ReduceDelayedClose &&
    00922           (UdfData.DelayedCloseCount > UdfData.MinDelayedCloseCount)))) {
    00923
    00924         Entry = UdfData.DelayedCloseQueue.Flink;
    00925
    00926         while (Entry != &UdfData.DelayedCloseQueue) {
    00927
    00928             //
    00929             //  Extract the IrpContext.
    00930             //
    00931
    00932             NextIrpContextLite = CONTAINING_RECORD( Entry,
    00933                                                     IRP_CONTEXT_LITE,
    00934                                                     DelayedCloseLinks );
    00935
    00936             //
    00937             //  If no Vcb was specified or this Vcb is for our volume
    00938             //  then perform the close.
    00939             //
    00940
    00941             if (!ARGUMENT_PRESENT( Vcb ) || (NextIrpContextLite->Fcb->Vcb == Vcb)) {
    00942
    00943                 RemoveEntryList( Entry );
    00944                 UdfData.DelayedCloseCount -= 1;
    00945
    00946                 IrpContext = (PIRP_CONTEXT) NextIrpContextLite;
    00947                 break;
    00948             }
    00949
    00950             //
    00951             //  Move to the next entry.
    00952             //
    00953
    00954             Entry = Entry->Flink;
    00955         }
    00956     }
    00957
    00958     //
    00959     //  If the Vcb wasn't specified and we couldn't find an entry
    00960     //  then turn off the Fsp thread.
    00961     //
    00962
    00963     if (!ARGUMENT_PRESENT( Vcb ) && (IrpContext == NULL)) {
    00964
    00965         UdfData.FspCloseActive = FALSE;
    00966         UdfData.ReduceDelayedClose = FALSE;
    00967     }
    00968
    00969     //
    00970     //  Unlock the global data.
    00971     //
    00972
    00973     UdfUnlockUdfData();
    00974
    00975     return IrpContext;
    00976 }
    00977
    00978