[CDFS_NEW] -> [CDFS] No old driver, thus no new driver
[reactos.git] / drivers / filesystems / cdfs / close.c
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 \f
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 \f
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 \f
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